Failure Reasons
The complete catalog of reason codes returned on failed payments, transfers and refunds — with their meaning and recommended action.
When a payment, transfer or refund fails, the object and webhook carry a reason
field: a stable, machine-readable code. This page lists them all. Branch your
logic on reason, never on the human-readable message (which may change).
Where to find it
The reason appears on the object (transaction.reason) and in the webhook payloads
payment.failed, transfer.failed, and refund_failed (in case of refund failure).
Payments — payment.failed
reason | Meaning | Recommended action |
|---|---|---|
insufficient_funds | Insufficient Mobile Money / card balance. | Ask the customer to top up and try again. |
operator_declined | The operator declined the transaction. | Try again later or offer another channel. |
customer_canceled | The customer canceled on their phone. | Offer to restart the payment. |
authorization_timeout | The customer did not validate in time (USSD/app). | Initialize a new transaction. |
invalid_number | Invalid or unregistered Mobile Money number. | Fix the number on the client side. |
wrong_pin | Incorrect PIN submitted on the operator side. | Invite the customer to try again. |
limit_exceeded | Operator/KYC limit for the customer exceeded. | Reduce the amount or switch methods. |
card_declined | Card declined by the issuing bank. | Try another card or Mobile Money. |
3ds_failed | 3-D Secure authentication failed. | Retry the card payment. |
fraud_blocked | Blocked by Shield or the operator. | Do not automatically retry; investigate. |
channel_unavailable | The channel is temporarily unavailable. | Retry or let orchestration fall over. |
Transfers — transfer.failed
reason | Meaning | Recommended action |
|---|---|---|
invalid_recipient | The recipient number/account is invalid. | Correct the recipient before replaying. |
recipient_unregistered | The recipient wallet does not exist. | Verify the number and operator. |
insufficient_balance | Your available balance is insufficient. | Top up and retry. |
limit_exceeded | The recipient's receiving limit exceeded. | Split the amount. |
operator_unavailable | The destination operator is unreachable. | Retry later (funds are re-credited). |
duplicate_transfer | Idempotency key already used. | Check the original transfer status. |
compliance_hold | Payout held for compliance review. | Contact support. |
Refunds & disputes
reason | Meaning | Recommended action |
|---|---|---|
wallet_unreachable | The customer's wallet is temporarily unreachable. | Retry the refund. |
refund_window_expired | The operator refund window has passed. | Refund via manual Transfer. |
already_refunded | The payment is already fully refunded. | No action. |
Intelligent retries
Some reasons are transient (operator_declined, channel_unavailable,
operator_unavailable) and warrant a retry; others are definitive (invalid_number,
invalid_recipient, fraud_blocked) and should not be replayed without correction. See
error handling.