---
title: "Status & Error Codes"
description: "HTTP status codes, transaction status ids, and the response envelope."
canonical: "https://eps.eko.in/docs/error-codes"
---


> **Canonical URL:** https://eps.eko.in/docs/error-codes
> This is a machine-readable Markdown version of the page for AI agents and LLMs. The primary (HTML) version lives at the canonical URL above.

# 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`](#frontend-display-status-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](#authentication-errors-http-401) |
| `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:

```json
{
	"status": 2485,
	"response_type_id": 2485,
	"response_status_id": 1,
	"message": "Expired security headers (secret-key-timestamp older than 2 minutes)"
}
```

{/* Keep in sync with AUTH_ERROR_CODES in src/lib/data/api-error-codes.ts (api-error-codes.test.ts checks the status + message columns). */}

| 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](/docs/how-auth-works#try-it-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](/docs/how-auth-works#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](#frontend-display-status-response_status_id).     |
| `response_type_id`   | number | Response type id for non-financial requests.                                                              |
| `tx_status`          | string | Financial transaction state (`"0"` = success); see [below](#financial-transaction-status-codes-tx_status) |
| `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:

```json
{
	"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](/docs/transaction-inquiry) rather than retrying the debit.

{/* Keep in sync with TX_STATUS_CODES in src/lib/data/api-error-codes.ts (single source for every generated surface). */}

| 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](#authentication-errors-http-401).

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:

- `-1` is used when information is being pulled (read-only) and the result is
  self-explanatory — e.g. get customer profile, or get list of recipients.
- `0` is used for financial transactions, or where data was modified at the
  backend — e.g. payment successful, or recipient deleted successfully. When
  `response_status_id` is `0`, 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.
