Skip to main content
Kwugwo uses conventional HTTP status codes: 2xx means success, 4xx means the request can’t succeed as sent, and 5xx means something went wrong on our side or at the PSP.
Branch on the HTTP status first, then on code (business errors) or errors[].field (validation errors). Log message, but don’t match on its text.

Status codes

A declined payment or refund is not an HTTP error. It comes back as 200 with status: "failed" and an error object on the activity or refund.

Error bodies

Bodies are always JSON. Their shape depends on the kind of error:
string
A stable, machine-readable class. See Error codes.
string
A specific message key (sometimes the PSP’s own text). Each endpoint’s Errors table lists the ones it returns.
array | object
Values for placeholders in message. Usually empty.

Error codes

Retries and idempotency

Kwugwo has no Idempotency-Key header. Use ref instead: it is unique per workspace on ugwos and refunds, so a retried create can never produce a duplicate.

Common pitfalls

The header must be exactly Authorization: Bearer sk.…. Check for a trailing newline from your secrets store, and that you’re using the sandbox key against sandbox-api.kwugwo.africa (or the live key against api.kwugwo.africa). Regenerating a key revokes the old one immediately.
Medium parameters belong in data.medium_params, not directly in data. A provider placed at data.provider is ignored, so the request fails as if you sent none. See Charge an ugwo.
IDs are scoped to the workspace and environment of the key. A sandbox ID (ending in _t) is never found with a live key.
amount_too_low / amount_too_high: amounts are in the smallest unit, so ₦5,000 is 500000. currency_not_allowed: none of your PSPs is set up for that currency.
The ugwo has checkout: null. Pass a checkout on create, or set up routing rules in the dashboard so one is picked automatically.
None of the PSPs on the checkout’s route could take the charge (for example, every PSP on the route rejected it or is unavailable). No activity is created, no webhooks are sent, and the ugwo stays requires_ugwo. Retry after a short wait or offer another medium, and check your PSP connections and routing rules in the dashboard. If you set a custom failure message in your routing rules, it’s returned as-is in message, so you can show it to the customer.For mediums that take a provider (ussd, pay_with_bank), a bank that no PSP on the checkout supports is rejected earlier, with a 422 on provider.
The ugwo is already paid (or refunded) or was cancelled. Fetch it to check status; there is nothing left to collect.
Check status. A PSP declining a refund is a normal outcome: "status": "failed" with the reason in error. For bank-transfer and USSD payments, you may need to send a destination.