err_code. Branch on it, not on message. When a field is wrong, errors names it.
{
"status": false,
"message": "Bad Request",
"data": null,
"err_code": "REQ_FIELD_MISSING",
"errors": { "customer_id": ["This field is required."] }
}
Fix and resend
Most
400 and 401 codes. Sending the same request again won’t help.Retry with backoff
429, 500, 503 and NET_TIMEOUT. Wait 1s, double each time, stop after 3 to 5 tries.Stop and escalate
RISK_AML_FAILED, or a 5xx that keeps coming back. Contact support@zapyd.com.General
Any endpoint can return these.| Code | HTTP | Meaning | What to do |
|---|---|---|---|
AUTH_MISSING_HEADERS | 401 | Missing authentication headers | Send X-API-KEY, X-TIMESTAMP and X-SIGNATURE on every request. |
AUTH_INVALID_SIGNATURE | 401 | Invalid signature | Rebuild the signature from the API key, timestamp and canonical body. GET requests sign {}. See Authentication. |
AUTH_UNAUTHORIZED | 401 | Unauthorized | Check the API key is active and belongs to this environment (sandbox or production). |
NOT_FOUND | 404 | Not found | Check the path, including the module prefix such as /cms/api/v1. |
TOO_MANY_REQUESTS | 429 | Too many requests | Back off and retry. |
NET_TIMEOUT | 400 | Request timed out | Retry with backoff. Before retrying an initiate call, check the order history so you don’t create the order twice. |
UNKNOWN_ERROR | 400 | Unknown error | Retry once. If it repeats, contact support with the request time. |
SYS_INTERNAL_ERROR | 500 | Internal server error | Retry with backoff. If it persists, contact support with the request time. |
SYS_SERVICE_UNAVAILABLE | 503 | Service unavailable | Retry with backoff. |
Request validation
Every code from here down returns HTTP400.
| Code | Meaning | What to do |
|---|---|---|
REQ_FIELD_MISSING | Mandatory field is missing | errors lists the missing fields. Add them. |
INPUT_MALFORMED | Malformed input | errors lists the fields with a blank, badly formatted or too-long value. |
INPUT_MALFORMED_ADDITIONAL_INFO | Malformed additional_info | Fix the shape of the additional_info object. |
INPUT_INVALID_DATE_FORMAT | Invalid date format | Send dates in the format the endpoint documents. |
INPUT_INVALID_PARAMETER | Invalid user ID | Check the customer_id you sent. |
REQ_INVALID_COUNTRY | Invalid country code | Send an ISO 3166 alpha-3 code, such as IND. |
REQ_INVALID_RESIDENCE_COUNTRY | Invalid residence country code | Send an ISO 3166 alpha-3 code for the country of residence. |
REQ_NON_RESIDENT_UNSUPPORTED | Non-residents not supported | The customer must live in the country they onboard in. |
Customers
| Code | Meaning | What to do |
|---|---|---|
USR_NOT_FOUND | Customer not found | Check the customer_id. |
AUTH_ORG_MISMATCH | Customer belongs to another organization | Use IDs created with your own API key, in the same environment. |
USR_DUPLICATE_CONTACT | Phone or email is linked to another customer | Look up the existing customer, or use different contact details. |
USR_UNVERIFIED | Customer is unverified | Finish KYC first. The customer must be VERIFIED. |
KYC
| Code | Meaning | What to do |
|---|---|---|
KYC_INVALID_AADHAAR_INPUT | Aadhaar input is incomplete | Send both document_front_image_url and document_back_image_url, or aadhaar_json inside additional_data. |
KYC_INVALID_DOC_TYPE | Document type not supported for the country | Pick a type from Fetch KYC Configuration. |
KYC_IN_USE | These KYC details belong to another customer | Each identity can verify only one customer. |
KYC_UPDATE_LIMIT_EXCEEDED | KYC update limit reached | Contact support to update this customer again. |
Bank accounts
| Code | Meaning | What to do |
|---|---|---|
BANK_DUPLICATE_ACCOUNT | UPI ID or account number is already in use | An account can belong to one customer only. |
BANK_LIMIT_REACHED | 3 accounts already added | A customer can have 3 active accounts per rail. Delete one first. |
BANK_NOT_FOUND | Bank account not found, or not this customer’s | Check the bank_id belongs to this customer_id. |
BANK_ACCOUNT_UNVERIFIED | Bank account is unverified | Wait for the BANK webhook. In sandbox, use Mock Bank Verification. |
BANK_MODE_MISMATCH | Bank account doesn’t match the payment method | Use a bank account on the same rail as payment_method. |
Orders
Payins and payouts share these codes with aPAYIN_ or PAYOUT_ prefix.
| Code | Meaning | What to do |
|---|---|---|
PAYIN_AMOUNT_ZERO_OR_NEGATIVEPAYOUT_AMOUNT_ZERO_OR_NEGATIVE | Amount is zero or negative | Send a positive amount. |
PAYIN_AMOUNT_BELOW_MINPAYOUT_AMOUNT_BELOW_MIN | Amount is below the minimum | Read the minimum from the configuration endpoint. |
PAYIN_AMOUNT_ABOVE_MAXPAYOUT_AMOUNT_ABOVE_MAX | Amount is above the maximum | Read the maximum from the configuration endpoint, or split the order. |
PAYIN_DUPLICATE_CLIENT_REF_IDPAYOUT_DUPLICATE_CLIENT_REF_ID | client_reference_id already exists | The order already exists. Fetch it from history instead of creating it again. |
PAYIN_QUOTATION_NOT_FOUNDPAYOUT_QUOTATION_NOT_FOUND | Quotation not found | Check the quotation_id. |
PAYIN_QUOTATION_LINKEDPAYOUT_QUOTATION_LINKED | Quotation is linked to another order | Each quotation backs one order. Create a new quotation. |
PAYIN_QUOTATION_EXPIREDPAYOUT_QUOTATION_EXPIRED | Quotation has expired | Create a new quotation and initiate before its expiry_time. |
PAYOUT_INVALID_PAYOUT_ID | Invalid payout ID | Check the payout_id. |
PAYIN_DUPLICATE_UTR | UTR is linked to another payin | Each bank transfer reference can fund one payin. |
PAYIN_INVALID_UTR_FORMAT | Invalid UTR format | See Understanding UTR for the format per rail. |
Risk and compliance
| Code | Meaning | What to do |
|---|---|---|
RISK_EDD_REQUIRED | Enhanced due diligence required | Submit EDD, then retry once it’s approved. See Limits and EDD. |
RISK_DAILY_LIMIT_EXCEEDED | Daily limit exhausted | Check the customer’s limits endpoint, and try again the next day. |
RISK_IP_CHECK_FAILED | IP address check failed | Send the end user’s own IP address in risk_parameters. |
RISK_AML_FAILED | AML screening failed | The customer can’t transact. Don’t retry. Contact support if you think this is wrong. |
By endpoint
Every endpoint can also return the general codes, includingSYS_INTERNAL_ERROR.
Customers
Customers
| Endpoint | Codes |
|---|---|
POST /customer/create | REQ_INVALID_COUNTRY, REQ_NON_RESIDENT_UNSUPPORTED, REQ_INVALID_RESIDENCE_COUNTRY, REQ_FIELD_MISSING, INPUT_MALFORMED, USR_DUPLICATE_CONTACT |
GET /customer/{customer_id} | USR_NOT_FOUND, AUTH_ORG_MISMATCH |
GET /customer/list | INPUT_INVALID_DATE_FORMAT |
KYC
KYC
| Endpoint | Codes |
|---|---|
GET /kyc/configuration/{customer_id} | USR_NOT_FOUND, AUTH_ORG_MISMATCH |
POST /kyc/add-kyc-data | REQ_FIELD_MISSING, INPUT_MALFORMED, USR_NOT_FOUND, AUTH_ORG_MISMATCH, KYC_INVALID_AADHAAR_INPUT, KYC_INVALID_DOC_TYPE, KYC_IN_USE, INPUT_MALFORMED_ADDITIONAL_INFO |
PATCH /kyc/update-tax-info | REQ_FIELD_MISSING, INPUT_MALFORMED, USR_NOT_FOUND, AUTH_ORG_MISMATCH, KYC_IN_USE |
PATCH /kyc/update-document-info | REQ_FIELD_MISSING, INPUT_MALFORMED, USR_NOT_FOUND, AUTH_ORG_MISMATCH, KYC_IN_USE, KYC_INVALID_AADHAAR_INPUT, KYC_INVALID_DOC_TYPE |
PATCH /kyc/update-selfie-info | REQ_FIELD_MISSING, USR_NOT_FOUND, AUTH_ORG_MISMATCH, INPUT_MALFORMED_ADDITIONAL_INFO, KYC_UPDATE_LIMIT_EXCEEDED |
Bank accounts
Bank accounts
| Endpoint | Codes |
|---|---|
POST /bank/create | REQ_FIELD_MISSING, USR_NOT_FOUND, AUTH_ORG_MISMATCH, USR_UNVERIFIED, BANK_DUPLICATE_ACCOUNT, BANK_LIMIT_REACHED |
GET /bank/{customer_id}/{bank_id} | USR_NOT_FOUND, AUTH_ORG_MISMATCH, BANK_NOT_FOUND |
GET /bank/list/{customer_id} | USR_NOT_FOUND, AUTH_ORG_MISMATCH |
Payouts
Payouts
| Endpoint | Codes |
|---|---|
GET /payout/configuration | General codes only |
GET /payout/limits/{customer_id} | USR_UNVERIFIED |
GET /payout/fetch-rate | REQ_FIELD_MISSING |
POST /payout/quotation | REQ_FIELD_MISSING, INPUT_MALFORMED, USR_UNVERIFIED, PAYOUT_AMOUNT_ZERO_OR_NEGATIVE, PAYOUT_AMOUNT_BELOW_MIN, PAYOUT_AMOUNT_ABOVE_MAX, RISK_AML_FAILED, RISK_IP_CHECK_FAILED, RISK_DAILY_LIMIT_EXCEEDED, RISK_EDD_REQUIRED, BANK_ACCOUNT_UNVERIFIED, BANK_NOT_FOUND, SYS_SERVICE_UNAVAILABLE |
GET /payout/quotation/{quotation_id} | REQ_FIELD_MISSING |
POST /payout/initiate | REQ_FIELD_MISSING, INPUT_MALFORMED, PAYOUT_DUPLICATE_CLIENT_REF_ID, PAYOUT_QUOTATION_NOT_FOUND, PAYOUT_QUOTATION_LINKED, PAYOUT_QUOTATION_EXPIRED |
GET /payout/{payout_id} | REQ_FIELD_MISSING, PAYOUT_INVALID_PAYOUT_ID |
GET /payout/history | REQ_FIELD_MISSING, INPUT_MALFORMED |
POST /payout/edd/save | USR_UNVERIFIED, REQ_FIELD_MISSING, INPUT_MALFORMED |
GET /payout/edd/list | INPUT_INVALID_PARAMETER |
Payins
Payins
| Endpoint | Codes |
|---|---|
GET /payin/configuration | General codes only |
GET /payin/limits/{customer_id} | USR_UNVERIFIED |
GET /payin/fetch-rate | REQ_FIELD_MISSING, INPUT_MALFORMED |
POST /payin/quotation | REQ_FIELD_MISSING, INPUT_MALFORMED, USR_UNVERIFIED, PAYIN_AMOUNT_ZERO_OR_NEGATIVE, PAYIN_AMOUNT_BELOW_MIN, PAYIN_AMOUNT_ABOVE_MAX, RISK_AML_FAILED, RISK_IP_CHECK_FAILED, RISK_DAILY_LIMIT_EXCEEDED, RISK_EDD_REQUIRED, BANK_ACCOUNT_UNVERIFIED, BANK_NOT_FOUND, BANK_MODE_MISMATCH, SYS_SERVICE_UNAVAILABLE |
GET /payin/quotation/{quotation_id} | REQ_FIELD_MISSING, INPUT_MALFORMED |
POST /payin/initiate | REQ_FIELD_MISSING, INPUT_MALFORMED, PAYIN_DUPLICATE_CLIENT_REF_ID, PAYIN_QUOTATION_NOT_FOUND, PAYIN_QUOTATION_LINKED, PAYIN_QUOTATION_EXPIRED, PAYIN_DUPLICATE_UTR, PAYIN_INVALID_UTR_FORMAT |
GET /payin/{payin_id} | REQ_FIELD_MISSING, INPUT_MALFORMED |
GET /payin/history | REQ_FIELD_MISSING, INPUT_MALFORMED |
POST /payin/edd/save | USR_UNVERIFIED, REQ_FIELD_MISSING, INPUT_MALFORMED |
GET /payin/edd/list | INPUT_INVALID_PARAMETER |