Appearance
Errors
When a request fails, Payd answers with an HTTP error status and a JSON body:
json
{
"error_code": "insufficient_balance",
"error_message": "insufficient balance",
"status_code": 400,
"request_id": "4bf92f3577b34da6"
}| Field | Meaning |
|---|---|
error_code | A stable snake_case code. Branch on this. |
error_message | Text you can log or show. It can change, so do not parse it. On a 5xx it is always a generic message. |
status_code | The HTTP status, repeated. |
request_id | The id of this request. Send it to support when you ask about an error. |
Some errors add extra string fields next to these four. Log them with the rest of the body.
Codes by HTTP status
| Status | error_code | Meaning | What to do |
|---|---|---|---|
400 | invalid_argument | A field is missing or not valid. The message names it. | Fix the request. Do not retry it unchanged. |
400 | insufficient_balance | Your balance does not cover the payout and its fee. | Top up, or pay out less. Check fees with a quote. |
400 | provider_error | The mobile money or bank network refused the payment, for example because the number is not registered. | Check the details with the customer. |
400 | invalid_form | The network refused a payout after Payd took the money from your balance. Payd has already put it back. | Check the recipient's details, then send a new payout. |
400 | beneficiary_inactive | The saved recipient you named is switched off. | Use another recipient. |
401 | user_unauthorized | The API key is missing or wrong. | Check the username and password. See authentication. |
403 | permission_denied | The key cannot act on that account, or the feature is not on for your account, such as card payments. | Use the account id from your key, or contact support. |
404 | resource_not_found | Payd has no record with that reference for your account, or nothing is set up for that country, currency and channel. | Check the reference or the payment option. |
405 | method_not_allowed | The path exists but not with this HTTP method. | Check the method. |
409 | duplicate_conflict | The record already exists, or the idempotency_key belongs to another payment, one that failed or one still running. The message says which. | Read the message. Check the status of the reference it names, or use a new key. |
429 | too_many_requests | You are sending requests too fast. | Wait, then retry with backoff. |
499 | request_cancelled | Your client closed the connection. | See retries and duplicates before you resend. |
500 | internal_error | Something failed inside Payd. | Check before you resend a payin or payout. |
501 | not_implemented | The endpoint does not exist. | Check the path. The changelog lists endpoints that moved. |
502 | bad_gateway | Payd could not reach an internal service. | Check, then retry. |
503 | service_unavailable | A service is down or busy. | Check, then retry with backoff. |
504 | gateway_timeout or request_timeout | Payd did not finish in time. The payment may still go through. | Search your payment requests before you resend. |
"Check" in this table means: for a payin or payout, find out whether the payment exists before you send it again. See retries and duplicates.
Messages you will see on payments
error_code | error_message starts with | Cause |
|---|---|---|
invalid_argument | missing required fields: | vendor_config, customer, provider_config or payment_config is missing, or vendor_config.account_id is empty. Send {} for an object you have nothing to put in. |
invalid_argument | payment_config.account_number or customer.phone_number is required | Payd does not know which phone or account to use. |
invalid_argument | send customer.customer_uid for a saved beneficiary, or customer.first_name and customer.last_name | The customer's first or last name is missing. |
invalid_argument | currency field not populated | currency is missing. |
invalid_argument | withdrawal pin not set for account | The key owner has not set a withdrawal PIN in the Payd Money App. |
invalid_argument | Complete your KYC before sending money to this country | The account holder's identity details are incomplete in the Payd Money App. |
invalid_argument | Nigeria needs a second form of identification | Your account is registered in Nigeria and has no BVN or NIN on file. See payouts across Africa. |
permission_denied | you do not have access to this account | vendor_config.account_id is not the account your key belongs to. |
permission_denied | this account is not activated for card payments | Ask support to switch card payments on. |
resource_not_found | account not found | The account id does not exist. |
The older collection endpoint
POST /api/v2/payments, the older M-Pesa collection endpoint, keeps the error body it always had:
json
{
"status": 400,
"success": false,
"message": "number (7458969711) is not valid kenyan number"
}Handle errors in code
js
const res = await fetch(url, options)
const body = await res.json()
if (!res.ok) {
console.error(`Payd ${body.status_code} ${body.error_code} (${body.request_id}): ${body.error_message}`)
if (body.error_code === 'insufficient_balance') return askForTopUp()
if (res.status >= 500) return checkBeforeRetrying()
throw new Error(body.error_message)
}python
res = requests.post(url, json=payload, auth=AUTH, timeout=35)
body = res.json()
if not res.ok:
print(f"Payd {body['status_code']} {body['error_code']} ({body.get('request_id')}): {body['error_message']}")
if body["error_code"] == "insufficient_balance":
ask_for_top_up()
elif res.status_code >= 500:
check_before_retrying()
else:
raise RuntimeError(body["error_message"])
