When something fails
The table that settles almost every question
Section titled “The table that settles almost every question”| What you see | Retry? | How |
|---|---|---|
status: "submitted" |
No | Wait for the webhook. It is already in progress |
status: "unknown" |
NEVER | It resolves on its own. Retrying here is how you pay twice |
status: "failed" + a data reason |
Yes, after fixing | Fix the beneficiary and request another quote |
status: "failed" + a payment network reason |
Yes | Another quote, without changing anything else |
502 upstream_error |
Yes | Retry with the same Idempotency-Key |
503 no_route_available |
Yes, later | There is no payment network right now for that bank/method |
429 rate_limited |
Yes, slower | Respect Retry-After |
Validation 4xx |
Not without fixing | The same body will fail the same way |
Ambiguous result: unknown
Section titled “Ambiguous result: unknown”What we do while the payment is in doubt:
-
Nothing is compensated. The entry stays as it is.
-
We query the payment network with our reference, with increasing backoff.
-
It gets resolved: paid →
settled; it does not recognize the reference after several queries → it is compensated and ends upfailed; returned →reversed. -
We notify you by webhook. No polling needed.
To keep an eye on it:
curl -s "$BASE/v1/payments?status=unknown&limit=100" -H "x-api-key: $KEY"Rejection: failed
Section titled “Rejection: failed”The entry is already reversed and you have not been charged anything
(feeAmount: "0", compensated: true). Retry with another quote as soon as
you fix the cause, which is in reason:
reason |
Whose problem it is | Useful retry |
|---|---|---|
beneficiary_missing_phone |
Yours: the beneficiary’s mobile number is missing for pago móvil | After adding phone |
beneficiary_missing_account |
Yours: the account is missing | After adding it |
beneficiary_mismatch |
Yours: name or national ID do not match the holder | After fixing it. No payment network would accept it |
invalid_destination_account |
Yours: the account does not exist or is wrong | After fixing it |
sender_required |
Yours: there was no sender | By sending the sender block |
sender_phone_unsupported |
The payment network’s: none available accepted the sender’s international phone number | With a Venezuelan mobile number for the sender, or later |
amount_below_minimum |
The amount’s: below the payment network’s floor | By raising the amount |
amount_above_limit |
The amount’s: above the ceiling | By splitting it |
bank_unreachable |
The payment network’s: it does not cover that bank | Another one was already tried; check the method’s catalog |
payout_insufficient_balance |
The paying account’s: no balance for the payment and the fee | After topping it up, or later |
payout_balance_unavailable |
The payment network’s: the balance could not be read, nothing was sent | Yes, in a few seconds |
no_route |
The combination’s: no payment network available | Try the other method |
A method goes down
Section titled “A method goes down”If the method you asked for is not available and methodPolicy is
preferred (the default), the payment goes out through the other one:
{ "status": "submitted", "method": "transferencia", "methodRequested": "pago_movil", "methodChanged": true }The status is still submitted: the method switch already happened, but the
transfer is still settling. With methodPolicy: "strict" the payout fails
instead of switching method.
Return of an already settled payment
Section titled “Return of an already settled payment”Days later, the bank may return a transfer (closed account, wrong data). The
event is verified and deduplicated, the entry is reversed —the payment moves
to reversed and the funds go back to your balance— and you receive
payment.reversed with the reason the bank reported. Your part is to let your
user know.
If your webhook receiver goes down
Section titled “If your webhook receiver goes down”We retry with increasing backoff (5 s → 6 h, 12 attempts). Once they run out, the event goes to your failed queue, queryable and redeliverable.
curl -s "$BASE/v1/events?status=dead" -H "x-api-key: $KEY"curl -s -X POST "$BASE/v1/events/retry-dead" -H "x-api-key: $KEY"See webhooks.
Reproduce all of this before production
Section titled “Reproduce all of this before production”Each case can be triggered in the test
environment: mode: "reject" with
method for the method switch, mode: "timeout_after_submit" for the payment
in doubt, /sandbox/bank/payout-settled and /sandbox/bank/payout-returned
for late confirmation and return, and /sandbox/webhooks/failing for your
retries.
curl -s -X POST $BASE/sandbox/chaos -H 'content-type: application/json' \ -d '{"mode":"timeout_after_submit"}'