Skip to main content

Failure details

There is no substatus field in the order contract. When an Order has status: "FAILED", the additional detail is carried by two free-form, nullable string fields on the order itself: failure_code and failure_reason.

Fields​

FieldTypeDescription
failure_codestring | nullA short, free-form code identifying the cause. Not a closed catalog β€” treat it as an opaque label for logging/support, not a value to switch on exhaustively.
failure_reasonstring | nullA human-readable explanation of the failure.

They are populated on reads (GET /orders/{id}, GET /orders) once something goes wrong; the response to the initial POST /orders call may not carry them yet, since the order has not reached a terminal state at that point.

Two things to code defensively around:

  • FAILED is not the only status that carries them. An order that failed and had its funds returned reports status: "COMPENSATED" with the failure_code of the original failure still attached. Do not gate reading these fields on status === "FAILED".
  • failure_reason can be an empty string, not just null. A check like reason === null will miss it; use a falsy check.

Example​

{
"id": "cpg_txn_a1b2c3d4e5f6",
"status": "COMPENSATED",
"failure_code": "PROVIDER_CANCELLED",
"failure_reason": ""
}

The same pair arrives on the webhook​

You do not have to poll to see this. The order status webhook carries the identical two values under different names:

On the orderOn the webhook event
failure_codereason
failure_reasonmessage

Same strings, same source, no translation in between. Whatever you learn to recognize in one place works in the other.

Payout failure codes (RET-*)​

When a payout is rejected at the disbursement network, failure_code carries a RET- code. These come from our long-standing payout platform and their meanings have not changed, so they are safe to recognize β€” but keep reading the caveat below the table before you build on them.

CodeWhat happenedCause lies with
RET-001The phone number is invalid, not registered, or cannot receive payments.Beneficiary data
RET-002The attempt timed out β€” either waiting, or on the provider's response.Provider
RET-003The recipient's account type is wrong or not valid for this operation.Beneficiary data
RET-004The recipient's person type does not meet the defined criteria.Beneficiary data
RET-005The transaction was rejected as invalid or unauthorized.Provider
RET-006The recipient cancelled the transaction before it completed.Recipient
RET-007The service is unavailable, or only operates in person (over the counter).Provider
RET-008The phone and the recipient's ID/RIF do not match, or are not registered.Beneficiary data
RET-009One or more fields have format errors.Beneficiary data
RET-010The selected financial institution is unavailable right now.Provider
RET-012The recipient's ID or RIF is invalid.Beneficiary data
RET-013The recipient's bank account is invalid or not registered.Beneficiary data
RET-018The nationality on the ID/RIF is not valid.Beneficiary data
RET-019The authorization network is unavailable right now.Provider
RET-020The submitted data has errors or does not meet the expected requirements.Beneficiary data
RET-026The recipient's number is wrong or not enrolled in the system.Beneficiary data
RET-028Available balance is insufficient to complete the transaction.Balance
RET-029The destination bank is not enrolled, authorized, or active for mobile payments.Provider
RET-033The transaction exceeds the daily amount allowed.Limits
RET-034The transaction exceeds the monthly amount allowed.Limits
RET-035The daily count of allowed payments has been exceeded.Limits
RET-036The monthly count of allowed payments has been exceeded.Limits
RET-044The recipient's bank account is closed.Beneficiary data
RET-045The recipient's bank account is inactive.Beneficiary data
RET-050The amount exceeds the maximum allowed for a single transaction.Limits
RET-055The phone number is not enabled to receive payments.Beneficiary data
RET-056The operation amount is above the maximum allowed.Limits
RET-9999An unexpected error occurred. Try again, or contact support.Unknown

"Cause lies with" is a reading aid, not a field. It is our grouping of the descriptions above, to save you triaging 28 rows by hand; nothing in the API returns it. Beneficiary data means a corrected payment_instructions can succeed. Limits and Balance mean the request was well-formed but did not fit. Provider means retrying later may work and nothing on your side needs changing.

note

failure_code and failure_reason are free-form strings, not a fixed error catalog β€” for the structured error contract returned on failed API calls (4xx/5xx responses), see Error codes.