Build

Errors

Every error is JSON. request_id is the id to quote if you ask for help. param is present when one field is the problem.

Error
{
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Available balance is not enough for this payout.",
    "request_id": "req_..."
  }
}
HTTPCodeWhat to do
400VALIDATION_ERRORFix the field named in param. Amounts are decimal strings. Phones are E.164.
401INVALID_API_KEYThe key is missing, revoked, or for the wrong environment.
401INVALID_CREDENTIALSThe portal password is wrong, or the account is locked.
403INSUFFICIENT_SCOPEThe key does not include that action.
403MERCHANT_NOT_ACTIVEThe account is not allowed to move money yet.
403LIMIT_EXCEEDEDThe amount is over the merchant limit.
404PAYMENT_NOT_FOUNDThat payment id is not on this merchant.
404PAYOUT_NOT_FOUNDThat payout id is not on this merchant.
409IDEMPOTENCY_KEY_REUSEDThe key was already used with a different body. Use the original response, or choose a new key for a new request.
409IDEMPOTENCY_IN_PROGRESSThe same key is still running. Wait, then retry that same key.
409INSUFFICIENT_BALANCETop up before the payout. Nothing was reserved.
422PROVIDER_UNAVAILABLENo route is configured, or the rail is down. Retry later.
422FEE_EXCEEDS_AMOUNTThe fee is larger than the amount. Increase the amount or change the fee setup.
429RATE_LIMITEDWait and retry. Retry-After is in seconds.

A collection can also succeed at the HTTP layer and then fail on the wallet. That failure is on the payment: status failed and a failure_message. A blank rejection is shown as “The payment was rejected.”

How to handle one

Read error.code first. Show error.message to the person who can fix the request. Store request_id with your log line. If param is present, the named field is the one to change. Do not retry a 400 or a 409 IDEMPOTENCY_KEY_REUSED unchanged. Do retry a 429 after Retry-After, and retry a timed-out create with the same idempotency key.

Payment failure is not this object

When the HTTP status is 201, there is no error object. A later wallet refusal is status: failed on the payment, with failure_message. Your order system should listen for that on the webhook, not only for HTTP errors.