Errors
Every refusal on /v1 answers JSON with the Error body. Branch on error.code: it is stable and catalogued, in
upper case. The merchant API’s own refusals carry the code alone; a refusal it relays from the switch keeps the
message_en and message_fr the switch gave, as below. A payout route’s own refusals answer MerchantPayoutError,
the same body with a shortfall: what the payout balance lacks for INSUFFICIENT_PAYOUT_BALANCE, null for any other
code, as the payouts guide shows. An invoice route’s own refusals answer MerchantInvoiceError, the
same body with message_en and message_fr always given, as the invoices guide shows.
{ "error": { "code": "SWITCH_UNAVAILABLE", "message_en": "Retry with the same key", "message_fr": "Réessayez avec la même clé" }}Every authenticated /v1 response carries X-Request-Id, the ID the request log keeps for that call: give it when
you ask about one. A request the server refuses before routing it, such as a firewall rejection, answers
{timestamp, status, error, path} instead, and no page is ever HTML.
A 503 can leave the outcome unknown: retry the exact request with its original Idempotency-Key, which never
creates a second payment or payout, and read the payment or payout before you create another.
Codes by status
Section titled “Codes by status”400 Bad Request
| Code | When |
|---|---|
INVALID_REQUEST |
The request breaks the contract: a missing or malformed field, header or parameter, or another refusal of the framework without a code of its own. |
INVALID_CURSOR |
The delivery list did not seal this cursor. |
401 Unauthorized
| Code | When |
|---|---|
INVALID_API_KEY |
The key is missing, unknown, revoked or a live key; it is checked on every request, replays included. |
403 Forbidden
| Code | When |
|---|---|
INSUFFICIENT_SCOPE |
The key lacks the permission the route needs, or no permission rule covers the route. |
SCOPE_ESCALATION |
A key asked for permissions beyond its own, keys:manage among them, which no key ever grants, including by rotating a key that holds it. |
404 Not Found
| Code | When |
|---|---|
PAYMENT_NOT_FOUND |
The payment is unknown or belongs to another merchant. |
ROUTE_NOT_FOUND |
No route answers at this address under a covered prefix. |
LINK_NOT_FOUND |
The payment link is unknown or belongs to another merchant, or a list’s cursor names no link of this merchant. |
BRANCH_NOT_FOUND |
The store named for a new link is not this merchant’s. |
PAYOUT_NOT_FOUND |
The payout is unknown or belongs to another merchant, or a list’s cursor names no payout of this merchant. |
PAYOUT_BATCH_NOT_FOUND |
The payout batch is unknown or belongs to another merchant, or a list’s cursor names no batch of this merchant. |
PAYOUT_LINE_NOT_FOUND |
The batch line is unknown or belongs to another merchant, or a cursor names no line of this batch. |
NAME_ENQUIRY_NOT_FOUND |
The name enquiry a payout names is unknown or belongs to another merchant. |
INVOICE_BATCH_NOT_FOUND |
The invoice batch is unknown or belongs to another merchant, or a list’s cursor names no batch of this merchant. |
INVOICE_NOT_FOUND |
The invoice is unknown or belongs to another merchant, or a list’s cursor names no invoice of this batch. |
405 Method Not Allowed
| Code | When |
|---|---|
METHOD_NOT_ALLOWED |
The route does not answer this method; Allow lists those it does. |
406 Not Acceptable
| Code | When |
|---|---|
NOT_ACCEPTABLE |
The route cannot produce what Accept asks for. |
409 Conflict
| Code | When |
|---|---|
IDEMPOTENCY_CONFLICT |
The Idempotency-Key already belongs to another request or mode, a payout command’s key was first used more than 720 hours ago, or a chunk of invoices holds other invoices under a number the batch already received. |
METHOD_UNAVAILABLE |
A new direct admission is refused: its method is unavailable. Nothing is retained. |
PARTICIPANT_CAP_EXCEEDED |
A new direct admission is refused: the participant’s cap is reached. Nothing is retained. |
INTENT_EXPIRED |
A new direct admission is refused: the intent has expired. Nothing is retained. |
DIRECT_PAYMENT_NOT_ADMITTED |
A new direct admission is refused. Nothing is retained. |
BRANCH_ARCHIVED |
A new direct admission is refused: the branch is archived. Nothing is retained. |
MERCHANT_LIMIT_EXCEEDED |
Above the merchant’s per-payment limit, the day’s or month’s in Kinshasa time for a direct payment, the day’s refunds limit, or the merchant’s payout limits, per payout or per day. |
PARTICIPANT_LIMIT_EXCEEDED |
A direct payment above the participant’s maximum per transaction. |
PAYMENT_NOT_CANCELLABLE |
The intent was submitted, is uncertain, ended or expired, or another original holds the key. |
REFUND_AMOUNT_EXCEEDED |
The refund asks for more than remains refundable. |
PAYMENT_NOT_REFUNDABLE |
The payment is not approved. |
REFUND_METHOD_UNSUPPORTED |
The payment’s method cannot be refunded yet. |
REFUND_WINDOW_EXPIRED |
The payment was approved more than 180 days ago. |
LINK_NOT_CANCELLABLE |
The link is paid or expired, or an attempt is under way; cancelling a cancelled link again answers it as it is. |
LINK_NOT_SHAREABLE |
The link is no longer payable. |
EVENT_NOT_SUBSCRIBED |
The event to replay is outside the current subscription. |
WEBHOOK_CHANGED |
The webhook configuration changed since the version you sent: read it again. |
STATEMENT_UNAVAILABLE |
A lot from before statements were recorded has none. |
STATEMENT_TOO_LARGE |
The statement would hold more than 10,000 lines. |
INSUFFICIENT_PAYOUT_BALANCE |
The available payout balance does not cover the payout’s or the batch’s amounts and fees: shortfall gives what is missing. Nothing is reserved. |
NAME_ENQUIRY_STALE |
The payout’s name enquiry is more than 24 hours old. |
NAME_ACKNOWLEDGEMENT_REQUIRED |
The name enquiry could not give the holder’s name and the payout does not acknowledge it. |
PAYOUT_DESTINATION_UNKNOWN |
The participant does not know the payout’s destination account. |
PAYOUT_ROUTE_UNAVAILABLE |
The participant takes no payouts at the moment, or a decision accepts or keeps a ROUTE_PAUSED line. |
PAYOUTS_HELD |
Futa holds the merchant’s payouts: nothing is sent or approved. |
PAYOUT_BATCH_TOO_LARGE |
The merchant’s open payout batches are at their bound of 20, or a chunk’s lines would pass those the batch announced, or all have arrived. |
PAYOUT_BATCH_INVALID |
A line is in another currency or numbered beyond those announced or received, a decision does not fit its line, a submission has no valid line, or the batch would keep one more preparer or key holder than it can. |
PAYOUT_BATCH_NOT_VALIDATED |
The batch is not VALIDATED: its lines are still arriving or being checked, it was submitted or lapsed, or lines are still to review at submission. |
PAYOUT_BATCH_CHANGED |
The batch’s version is no longer the one you sent: read it again. |
PAYOUT_LINE_NOT_RETRYABLE |
The batch has no failed line left that a retry may send. |
RESULT_NOT_READY |
The batch has not reached the state its report or result describes. |
INVOICE_BATCH_LIMIT_REACHED |
The merchant’s open invoice batches, those MAPPING, VALIDATING, RECEIVING or READY, are at their bound of 20 (SYNTHETIC). |
INVOICE_BATCH_TOO_LARGE |
A chunk’s invoice is numbered beyond those the batch announced, or was received in another chunk. |
INVOICE_BATCH_CHANGED |
The batch’s version is no longer the one you sent, or the batch takes no more of this: its invoices have all arrived, it was made from a file, or it is being sent, was sent, failed to send, has lapsed or was discarded. Read it again. |
INVOICE_BATCH_NOT_VALIDATED |
The batch cannot be sent yet: its invoices have not all arrived, its file’s mapping is not confirmed or still being checked, or no invoice is ready. |
MESSAGES_NOT_CONFIGURED |
A channel was chosen outside the sandbox, where no message transport exists yet. |
MERCHANT_NAME_INVALID |
The merchant’s stored name fails the text rule, at most 120 code points once trimmed: the send is refused before anything is made. |
413 Content Too Large
| Code | When |
|---|---|
EXPORT_TOO_LARGE |
The export is too large: narrow the filters. No file is returned. |
REQUEST_TOO_LARGE |
The body exceeds 16 KiB, chunked bodies included, on a /v1 POST that does not bound its own body, or 512 KiB for a chunk of payout batch lines or of invoices; it is refused before it is read. |
415 Unsupported Media Type
| Code | When |
|---|---|
UNSUPPORTED_MEDIA_TYPE |
The request body is not JSON. |
429 Too Many Requests
| Code | When |
|---|---|
RATE_LIMITED |
The merchant’s shared quota is exhausted for now. |
NAME_ENQUIRY_RATE_LIMITED |
The merchant’s name-enquiry budget for the rolling hour is spent, for one destination, one person or key, or the merchant; Retry-After gives the seconds to wait. |
500 Internal Server Error
| Code | When |
|---|---|
INTERNAL_ERROR |
An unexpected failure, logged and never detailed. |
503 Service Unavailable
| Code | When |
|---|---|
SWITCH_UNAVAILABLE |
The switch did not answer: the outcome may be unknown. Retry the exact request with its original key. |
INVALID_CREATION_RESPONSE |
The switch’s answer to a creation was not valid: the outcome may be unknown. Retry with the original key. |
INVALID_CANCELLATION_RESPONSE |
The switch’s answer to a cancellation was not valid: the outcome may be committed. Retry with the original key. |
INVALID_LINK_RESPONSE |
The switch’s answer was not the closed link shape: nothing of it is relayed. Retry, a creation with its original key. |
SERVICE_UNAVAILABLE |
An asynchronous answer timed out. |
TOP_UP_UNAVAILABLE |
The sandbox’s sponsor simulator did not answer a top-up, or the sandbox has no simulator key: the outcome may be unknown. Send the same request again under the same key, which funds at most once. |
Codes the contract does not name yet
Section titled “Codes the contract does not name yet”The merchant API also answers these codes on /v1, which the public contract does not name yet. Publishing the full
catalogue of codes is an open gate; until then, branch on them as on the others.
| Code | Status | When |
|---|---|---|
EVENT_NOT_FOUND |
404 | The event whose attempts you read or that you replay is not this merchant’s. |
INVALID_RECEIPT_REQUEST |
400 | A receipt was asked for with a query other than lang=fr or lang=en. |
KEY_NOT_FOUND |
404 | The key to rotate or revoke is not this merchant’s. |
KEY_REVOKED |
409 | The key to rotate is revoked. |
MERCHANT_NOT_FOUND |
404 | The merchant is disabled, for key and webhook management. |
REPLAY_RATE_LIMITED |
429 | The event was already replayed within the last minute. |
WEBHOOK_ALREADY_CONFIGURED |
409 | The merchant already has an endpoint: move it with POST /v1/webhooks/endpoint/configuration. |
WEBHOOK_NOT_FOUND |
404 | The merchant has no endpoint yet. |
The full contract states each operation’s refusals in the API reference.