Status & Error Codes
Eko APIs report status at two levels: the transport-level HTTP status code
and the business-level status inside the response envelope. A 200 OK
with a non-zero status is a successful call that returned a business error —
always check both. The envelope also carries a
response_status_id, which is a
UI display hint only — never use it for business logic.
HTTP Status Codes
| Code | Meaning |
|---|---|
200 | OK — response returned by our system. |
401 | Unauthorized — authentication failed. Known causes are named by the body status: see Authentication errors |
404 | Not Found — wrong request URL. |
405 | Method Not Allowed — incorrect HTTP method. |
415 | Unsupported Media Type — wrong Content-Type header. |
500 | Internal Server Error — connectivity or URL misconfiguration. |
Authentication errors (HTTP 401)
When authentication fails, the API returns HTTP 401 and a response body
whose status (and response_type_id, which carries the same value) tells you
which check failed:
{
"status": 2485,
"response_type_id": 2485,
"response_status_id": 1,
"message": "Expired security headers (secret-key-timestamp older than 2 minutes)"
}
| status | message | Cause | Fix |
|---|---|---|---|
2483 | Unauthorized | developer_key is wrong | Send the developer_key for the environment you are calling |
2484 | Invalid secret-key or timestamp | secret-key (signature) is wrong | Sign the exact timestamp you send, keyed by base64(access_key) used as a string. Check it in the secret-key playground |
2485 | Expired security headers (secret-key-timestamp older than 2 minutes) | secret-key-timestamp is more than 2 minutes older or newer than our server clock, or was reused from an earlier request | Generate a new timestamp and secret-key for every request; keep your server clock synced (NTP) |
2486 | Invalid secret-key-timestamp (expected milliseconds since the UNIX epoch) | secret-key-timestamp is not in milliseconds (13 digits) — often seconds (10 digits) | Send milliseconds since the UNIX epoch |
2487 | Missing security headers | secret-key or secret-key-timestamp header is missing | Send both headers, spelled exactly secret-key and secret-key-timestamp |
These are the known codes. A 401 can also come from calling production with
UAT keys, or (in production) calling from an IP that isn't whitelisted — see
Troubleshooting a 401.
The Response Structure
| Field | Type | Meaning |
|---|---|---|
status | number | Primary success indicator (0 = success). |
response_status_id | number | UI display status — not for business logic. See below. |
response_type_id | number | Response type id for non-financial requests. |
tx_status | string | Financial transaction state ("0" = success); see below |
message | string | Human-readable result or error message. |
data | object | Rest of the response parameters specific to that transaction |
Input Validation Errors
In case of input parameter validation errors, you will receive and error (non-zero) status code, response_status_id = 1, response_type_id = -1, and the response will contain an invalid_params object with each invalid parameter name and its error message. This can be used to show proper error response in the user-input form itself.
For example:
{
"status": 461,
"response_status_id": 1,
"response_type_id": -1,
"invalid_params": {
"name": "Name too long",
"dob": "Must be over 18 years"
}
}
Financial Transaction Status Codes (tx_status)
Financial (money-debit) responses additionally carry tx_status and txstatus_desc. When tx_status is 2 (Initiated), or 6 (Response Awaited), poll Transaction Inquiry rather than retrying the debit.
| tx_status | Meaning |
|---|---|
0 | Success |
1 | Failed |
2 | Initiated / Response Awaited (NEFT) — poll Transaction Inquiry |
3 | Refund Pending |
4 | Refunded |
6 | Response Awaited — Transaction Inquiry required |
Common Transaction Status Codes (status)
For all financial transactions, status = 0 should be treated as successful else failed. The current state of a financial transaction can be retrieved from tx_status and txstatus_desc parameters.
For all non-financial requests, you may need to consider both status and response_type_id parameters.
Authentication failures (2483–2487) come with HTTP 401, not 200 — see
Authentication errors.
Here are some of the common status codes:
| status | Meaning |
|---|---|
0 | Success |
17 | User wallet already exists |
132 | Sender name should only contain letters |
302 | Wrong OTP |
303 | OTP expired |
319 | Invalid initiator_id. User does not exist in our system |
327 | Enrollment done; verification pending |
342 | Recipient already registered |
346 | User/agent not onboarded or wrong user_code |
347 | Insufficient balance |
463 | User not found |
585 | Customer already KYC approved |
945 | Sender/beneficiary monthly limit exhausted |
1297 | User/Agent not onboarded |
Frontend Display Status (response_status_id)
response_status_id is similar to status, but its granularity is optimized for
frontend UX — it tells your UI how to present a result. Never use it to run
business or branching logic, or to decide whether a transaction succeeded or
failed. Use status for that (plus tx_status for financial transactions, and
response_type_id for non-financial requests).
For example, both -1 and 0 denote success, but:
-1is used when information is being pulled (read-only) and the result is self-explanatory — e.g. get customer profile, or get list of recipients.0is used for financial transactions, or where data was modified at the backend — e.g. payment successful, or recipient deleted successfully. Whenresponse_status_idis0, the UI can show a green tick or another marker to indicate a successful transaction.
| response_status_id | Meaning |
|---|---|
-1 | Success (read-only information pull) |
0 | Success (financial transaction, or backend state modified successfully). The UI may show a success stamp. |
1 | Failure |
2 | Transaction Initiated |
3 | Refund Initiated for the financial transaction |
4 | Financial Transaction Refunded |
If response_status_id is missing or unrecognized, show a neutral state and rely
on status for the outcome.