# Eko EPS integration rules — append to your existing .cursorrules

# Integrating Eko Platform Services (EPS) APIs

EPS is an API platform for payments, banking-correspondent services (AePS, DMT, BBPS) and identity verification (PAN, Aadhaar, bank, GST, etc.) in India. This pack tells an AI coding agent how to call EPS APIs correctly.

This is a self-contained section — append it to your repo's existing agent instructions (AGENTS.md or equivalent); it does not replace your project instructions. Agents with plugin support get richer, on-demand context instead of this static pack: see per-agent install at https://eps.eko.in/ai (EPS MCP + skills).

## Getting started

Start testing Eko verification APIs in ~10 minutes: sign up, verify identity, load your wallet, and test live before integrating.

1. **Sign up** — Sign up with your mobile number (OTP verified). (https://ekostore.app/eps)
2. **Verify identity** — Submit your PAN.
3. **Test live** — Load wallet funds; call the verification APIs live to evaluate before integrating.
4. **Integrate** — Free AI plugins/tools + MCP & SDKs to integrate faster. (https://eps.eko.in/ai)
5. **Go live** — Welcome email lists the KYC docs for production; reply with docs to get production keys.

## Environments

| Environment | Base URL | Notes |
| --- | --- | --- |
| UAT / Sandbox | https://staging.eko.in/ekoapi/v3 | Self-serve credentials available immediately on signup. |
| Production | https://api.eko.in/ekoicici/v3 | Credentials issued after organizational KYC. |

## Authentication & request signing

> **Backend-only. The access_key is a server-side secret used to compute the per-request secret-key (HMAC-SHA256). Never expose access_key or compute secret-key in a browser/frontend.**

Every request sends these headers:

| Header | Description |
| --- | --- |
| developer_key | Static API key issued to your account after KYC. |
| secret-key | Dynamic per-request signature: base64(HMAC-SHA256(timestamp, base64(access_key))). |
| secret-key-timestamp | Current time in milliseconds since UNIX epoch, used to compute secret-key. Must match server time. |
| content-type | application/json |

Compute `secret-key` (server-side) as:

1. Base64-encode the access_key.
2. Generate the current timestamp in milliseconds (as a string).
3. Compute HMAC-SHA256 of the timestamp using the base64-encoded key.
4. Base64-encode the resulting signature — this is the secret-key.

Full auth reference: https://eps.eko.in/docs/how-auth-works

## Error model

Responses carry `status` (0 = success) and a granular `response_status_id`. Common codes (e.g. `463` = user not found, `347` = insufficient balance). Full table: https://eps.eko.in/docs/error-codes.

Non-financial responses also carry `response_type_id`, which identifies *which* response shape came back and is the field to branch on when choosing the next call. Each API's documented values, their meaning and the endpoint to call next are in its `responseTypes` (https://eps.eko.in/agent/api/<slug>.json).

## API endpoints

| API | Method | Path | Summary |
| --- | --- | --- | --- |
| Get Sender Profile | GET | `/customer/payment/dmt-fino/sender/{customer_id}` | Fetch the DMT-Fino profile of a registered sender by mobile number. |
| Onboard Sender | POST | `/customer/payment/dmt-fino/sender/{customer_id}` | Register a new customer as a DMT-Fino sender using basic KYC details. |
| Sender eKYC (Biometric) | PUT | `/customer/payment/dmt-fino/sender/{customer_id}/otp` | Initiate biometric Aadhaar eKYC to verify and upgrade a DMT sender's account. |
| Validate eKYC OTP | PUT | `/customer/payment/dmt-fino/sender/{customer_id}/otp/verify` | Confirm sender eKYC by verifying the OTP sent to the Aadhaar-linked mobile. |
| Get Recipients | GET | `/customer/payment/dmt-fino/sender/{customer_id}/recipients` | Retrieve the list of saved beneficiaries for a DMT sender. |
| Add Recipient | POST | `/customer/payment/dmt-fino/sender/{customer_id}/recipient` | Register a new beneficiary under a sender's DMT-Fino account. |
| Send Transaction OTP | POST | `/customer/payment/dmt-fino/otp` | Request an OTP to the sender's mobile number to authorise an upcoming money transfer. |
| Initiate Transfer | POST | `/customer/payment/dmt-fino` | Execute a DMT-Fino money transfer after OTP verification. |
| Activate AePS Fingpay for Agent | PUT | `/admin/network/agent/{user_code}/aeps-fingpay/activate` | Enable AePS Fingpay service for your agent by submitting their biometric device details and KYC documents. |
| Get Shop Types | GET | `/user/collection/aeps-fingpay/get-Mcc-Category` | List the Merchant Category Codes (MCC) available for AePS Fingpay agent onboarding. |
| Get States | GET | `/user/collection/aeps-fingpay/get-states` | List the states (with their state_id) available for AePS Fingpay agent onboarding. |
| Send OTP (eKYC) | POST | `/user/collection/aeps-fingpay/kyc/otp` | Initiate AePS Fingpay eKYC by sending an OTP to the agent's registered Aadhaar-linked mobile number. |
| Verify OTP (eKYC) | PUT | `/user/collection/aeps-fingpay/kyc/otp/verify` | Verify the eKYC OTP sent to the agent's Aadhaar-linked mobile number to advance the one-time AePS Fingpay eKYC. |
| Biometric eKYC | PUT | `/user/collection/aeps-fingpay/kyc/biometric` | Complete one-time AePS Fingpay eKYC by submitting the agent's Aadhaar and live biometric fingerprint capture. |
| Daily KYC | PUT | `/user/collection/aeps-fingpay/kyc/biometric/daily` | Perform the mandatory daily biometric re-verification that authorises an agent to carry out AePS transactions for the current calendar day. |
| AePS Cash Withdrawal | POST | `/customer/collection/aeps-fingpay/cash-withdrawl/{customer_id}` | Withdraw cash from any Aadhaar-linked bank account using biometric fingerprint authentication — no card or PIN required. |
| AePS Balance Enquiry | POST | `/customer/collection/aeps-fingpay/balance-enquiry/{customer_id}` | Check a customer's bank account balance using Aadhaar number and biometric fingerprint — no card or PIN required. |
| AePS Mini Statement | POST | `/customer/collection/aeps-fingpay/mini-statement/{customer_id}` | Retrieve the last few transactions from an Aadhaar-linked bank account via biometric authentication. |
| Add Settlement Bank Account | POST | `/user/payment/aeps/settlement/account` | Register a bank account as an AePS fund-settlement recipient for an agent. |
| Get Settlement Bank Accounts | GET | `/user/payment/aeps/settlement/accounts` | List an agent's registered AePS settlement recipients with unsettled funds and remaining limit. |
| Initiate Settlement | POST | `/user/payment/aeps/settlement` | Settle an agent's AePS funds to a registered bank account via NEFT/IMPS/RTGS. |
| Get BBPS Categories | GET | `/customer/payment/bbps/categories` | Retrieve the list of supported BBPS biller categories (electricity, gas, DTH, etc.). |
| Get BBPS Locations | GET | `/customer/payment/bbps/locations` | Retrieve the list of supported state/location IDs for filtering BBPS operators. |
| Get BBPS Operators | GET | `/customer/payment/bbps/operators` | List all active BBPS billers, optionally filtered by category and/or state. |
| Get Operator Parameters | GET | `/customer/payment/bbps/operator/{operator_id}/parameters` | Fetch the custom input fields required by a specific biller before payment. |
| Get District Discome (UPPCL) | GET | `/customer/payment/bbps/operators/190/district-discome` | Resolve the district-level distribution company code required by UPPCL (operator 190). |
| Get Operator Code and Circle | GET | `/customer/payment/bbps/recharge/{customer_mobile}/operator` | Auto-detect a mobile number's recharge operator code and telecom circle. |
| Get Recharge Plans | GET | `/customer/payment/bbps/recharge/{customer_mobile}/operator/plans` | List the prepaid mobile / DTH recharge plans available for an operator and circle. |
| Fetch BBPS Bill | GET | `/customer/payment/bbps/bill` | Retrieve outstanding bill details from a biller before processing payment. |
| Pay BBPS Bill | POST | `/customer/payment/bbps` | Process a bill payment or recharge for any BBPS-connected biller. |
| Fetch PAN Details | POST | `/tools/kyc/fetch-pan` | Fetch the PAN holder's registered full name and category from the PAN number alone. |
| PAN Lite | POST | `/tools/kyc/pan-lite` | Instant PAN validation with name and DOB match scores plus Aadhaar seeding status. |
| PAN Advanced | POST | `/tools/kyc/pan-advanced` | Rich PAN verification returning registered name, PAN type, gender, DOB, masked Aadhaar, address, email, and mobile. |
| Bulk PAN Verification | POST | `/tools/kyc/pan/bulk` | Async batch PAN verification — submit multiple PANs in one call and poll for results via the Bulk PAN Status API. |
| Check Bulk PAN Verification Status | GET | `/tools/kyc/pan/bulk/status` | Poll the result of a Bulk PAN Verification batch using the reference_id returned when the batch was submitted. |
| Validate Aadhaar | POST | `/customer/payment/ppi-levin/sender/{customer_id}/aadhaar/otp` | Submit sender's Aadhaar number for OTP-based validation in the PPI Levin wallet onboarding flow. |
| Validate Aadhaar OTP | POST | `/customer/payment/ppi-levin/sender/{customer_id}/aadhaar/otp/verify` | Verify the Aadhaar OTP to complete identity validation in the PPI Levin wallet onboarding flow. |
| Get Sender Information | GET | `/customer/payment/ppi-levin/sender/{customer_id}` | Fetch a PPI Levin sender's wallet profile and onboarding/OTP state by mobile number. |
| Onboard Sender | POST | `/customer/payment/ppi-levin/sender/{customer_id}` | Register a new customer as a PPI Levin wallet sender using basic KYC details. |
| Verify Sender OTP | POST | `/customer/payment/ppi-levin/sender/{customer_id}/otp/verify` | Verify the sender OTP to authenticate the PPI Levin wallet and return the sender's profile and balance. |
| Validate PAN | POST | `/customer/payment/ppi-levin/sender/{customer_id}/pan` | Validate the sender's PAN to complete PPI Levin KYC and return the updated wallet profile. |
| Get List of Recipients | GET | `/customer/payment/ppi-levin/sender/{customer_id}/recipients` | Retrieve the list of saved beneficiaries for a PPI Levin sender. |
| Add Recipient | POST | `/customer/payment/ppi-levin/sender/{customer_id}/recipient` | Register a new beneficiary under a PPI Levin sender's account. |
| Add Recipient Bank | POST | `/customer/payment/ppi-levin/sender/{customer_id}/bank/recipient` | Register a bank beneficiary for an existing PPI Levin recipient. |
| Send Transaction OTP | POST | `/customer/payment/ppi-levin/otp` | Request an OTP to the sender's mobile to authorise a PPI Levin transfer. |
| Initiate Transaction | POST | `/customer/payment/ppi-levin` | Execute a PPI Levin wallet transfer to a recipient after OTP verification. |
| Get Sender Information | GET | `/customer/payment/ppi-digikhata/sender/{customer_id}` | Fetch a DigiKhata wallet sender's profile and onboarding/OTP state by mobile number. |
| Onboard Sender | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}` | Register a new customer as a PPI DigiKhata wallet sender using basic KYC details. |
| Generate Sender Verification OTP | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/otp` | Send a verification OTP to a DigiKhata sender's registered mobile number. |
| Verify Sender OTP | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/otp/verify` | Verify the sender OTP to authenticate the DigiKhata wallet and return the sender's profile and balance. |
| Get Aadhaar KYC Consent Languages | GET | `/customer/payment/ppi-digikhata/sender/{customer_id}/aadhaar/consent/languages` | List the languages available for the DigiKhata Aadhaar eKYC consent. |
| Get Aadhaar KYC Consent Details | GET | `/customer/payment/ppi-digikhata/sender/{customer_id}/aadhaar/consent/details` | Fetch the DigiKhata Aadhaar eKYC consent text and audio for a chosen language. |
| Generate Sender Aadhaar OTP | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/aadhaar/otp` | Validate a DigiKhata sender's Aadhaar number and trigger an OTP to the linked mobile. |
| Validate Sender Aadhaar OTP | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/aadhaar/otp/verify` | Verify the Aadhaar OTP to complete DigiKhata sender Aadhaar eKYC. |
| Validate Sender PAN | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/pan` | Validate the sender's PAN to complete DigiKhata KYC and return the updated wallet profile. |
| Load Sender DigiKhata Wallet | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/wallet/loadwallet` | Load funds into a DigiKhata sender's prepaid wallet. |
| Get List of Recipients | GET | `/customer/payment/ppi-digikhata/sender/{customer_id}/recipients` | Retrieve the list of saved beneficiaries for a DigiKhata sender. |
| Add Recipient | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/recipient` | Register a new beneficiary under a DigiKhata sender's account. |
| Generate Add Recipient Bank OTP | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/recipient/bank/otp` | Generate an OTP to register a recipient's bank for a DigiKhata sender. |
| Validate OTP to Add Recipient | POST | `/customer/payment/ppi-digikhata/sender/{customer_id}/recipient/bank/otp/verify` | Verify the OTP to complete recipient bank registration for a DigiKhata sender. |
| Send Transaction OTP | POST | `/customer/payment/ppi-digikhata/otp` | Request an OTP to the sender's mobile to authorise a DigiKhata transfer. |
| Initiate Transaction | POST | `/customer/payment/ppi-digikhata` | Execute a DigiKhata wallet transfer to a recipient after OTP verification. |
| Onboard User | POST | `/user/network/eps-agent` | Register a new agent/retailer (merchant) on the EPS platform and receive their user_code. |
| Activate Service for User | PUT | `/admin/network/agent/{user_code}/service/{service_code}/activate` | Activate a specific service (by service code) for one of your agents/retailers. |
| Deactivate Service for User | PUT | `/admin/network/agent/{user_code}/service/{service_code}/deactivate` | Deactivate a specific service (by service code) for one of your agents/retailers. |
| Get User's Services | GET | `/user/account/services` | Check the activation status of every service for one of your agents. |
| Get All Services | GET | `/tools/catalog/service-codes` | List every service available on the platform with its service code and provider. |
| Get Wallet Balance | GET | `/user/account/balance` | Fetch the wallet balance for a user. |
| Transaction Inquiry | GET | `/tools/reference/transaction/{transaction-reference}` | Get the status of any transaction by Eko TID or your client_ref_id. |
| Get Refund OTP | POST | `/customer/payment/refund/{tid}/otp` | Request the refund OTP for a failed transaction (sent to the customer's mobile). |
| Initiate Refund | POST | `/customer/payment/refund/{tid}` | Refund a failed transaction to the customer after OTP consent. |
| Get List of Banks | GET | `/tools/reference/banks` | Fetch a list of all banks. |
| Get Bank Details | GET | `/tools/reference/bank/{bank_code}` | Fetch a bank's details (id, name, channels) by its Eko bank code. |
| Get IFSC Details | GET | `/tools/reference/banks/ifsc/{ifsc}` | Resolve a bank and branch from an IFSC code. |
| Create DigiLocker URL | POST | `/tools/kyc/digilocker` | Generate a DigiLocker redirect URL to initiate consent-based Aadhaar document retrieval. |
| Get DigiLocker Document | POST | `/tools/kyc/digilocker/document` | Retrieve verified Aadhaar details from DigiLocker after the customer completes the consent journey. |
| DigiLocker Verification Status | GET | `/tools/kyc/digilocker/status` | Check whether a user has completed the DigiLocker consent and verification flow. |
| Bank Account Verification | POST | `/tools/kyc/bank-account/sync` | Verify a bank account by transferring ₹1 (penny drop) and retrieve the account holder name, account status, and branch details in real time. |
| Bulk Bank Account Verification | POST | `/tools/kyc/bank-account/bulk` | Submit multiple bank accounts for penny-drop verification in a single API call; poll a status API for per-account results. |
| Check Bulk Bank Account Verification Status | GET | `/tools/kyc/bank-account/bulk/status` | Poll for per-account results of a Bulk Bank Account Verification batch using the bulk_reference_id returned at submit time. |
| GST Verification | POST | `/tools/kyc/gstin` | Verify GSTIN details instantly — legal name, trade name, status, address, and filing metadata — for vendor onboarding and compliance checks. |
| Fetch GSTINs by PAN | POST | `/tools/kyc/gstin-with-pan` | Retrieve all GSTINs linked to a given PAN — with their state and status — in a single API call. |
| UPI ID (VPA) Verification | POST | `/customer/payment/upi/validate-vpa` | Validate a UPI Virtual Payment Address (VPA) and retrieve the registered payee name and mobile number in real time. |
| Driving License Verification | POST | `/tools/kyc/driving-license` | Verify driving license details in real time — holder name, DOB, address, validity, COV/badge class, and status. |
| Vehicle & RC Verification | POST | `/tools/kyc/vehicle-rc` | Verify a vehicle's registration certificate (RC) in real time — owner details, chassis/engine numbers, insurance validity, blacklist status, permits, fitness, and financier info via the VAHAN national database. |
| Employee Verification (Advance) | POST | `/tools/kyc/advance-employment` | Verify employment history and employee identity by phone number via EPFO/UAN data. |
| Reverse Geocoding | POST | `/tools/kyc/reverse-geocoding` | Convert latitude and longitude coordinates into structured Indian address data including locality, city, state, PIN code, and country. |
| Voter ID Verification | POST | `/tools/kyc/voter-id` | Validate EPIC (Voter ID) card details in real time against government records — returns name, age, address, constituency, and polling station information. |
| Passport Verification | POST | `/tools/kyc/passport` | Verify Indian passport application details using passport file number and date of birth. |
| CIN Verification | POST | `/tools/kyc/cin` | Verify Company Identification Numbers (CIN) against MCA records — returns company name, incorporation details, directors, and CIN status. |
| IP Verification | POST | `/tools/kyc/ip` | Geo-locate and risk-score an IP address in real time — detect proxies, VPNs, and assess fraud risk. |
| Name Match API | POST | `/tools/kyc/name-match` | AI-powered name comparison trained on 100M+ Indian name records — returns a match score (0–1) and match category for automated KYC decisions. |
| ITR Compliance Check | POST | `/tools/kyc/touras/itr-compliance` | Check income tax return filing and compliance status for a PAN holder in real time — ideal for lending, credit assessment, and financial due-diligence workflows. |
| DIN Verification | POST | `/tools/kyc/touras/din-verification` | Verify Director Identification Numbers (DIN) against MCA records — returns director name, DIN status, designation, and associated company information. |
| E-Challan Verification | POST | `/tools/kyc/touras/e-challan` | Fetch pending traffic challans for any vehicle using its registration number — challan number, offence, fine amount, date, status, and issuing authority returned in a single API call. |
| Email Verification | POST | `/tools/kyc/touras/check-email` | Verify an email address in real time — confirm the domain has live mail infrastructure, detect disposable addresses, and retrieve domain age as a trust signal. |
| FSSAI License Verification | POST | `/tools/kyc/touras/fetch-fssai` | Verify FSSAI food license details and status in real time. |
| Send OTP | POST | `/tools/kyc/mobile/otp` | Send a one-time password (OTP) to a customer's primary mobile number to start mobile verification. |
| Verify OTP | PUT | `/tools/kyc/mobile/otp/verify` | Verify the OTP entered by the customer and receive a signed verification token for downstream use. |
| Validate OTP-Verification-Token | GET | `/tools/kyc/mobile/otp/validate-token` | Validate an otp_verification_token as proof that OTP verification happened within the 5-minute time limit. |

Full machine-readable specs: https://eps.eko.in/agent/eps.json (index: https://eps.eko.in/agent/index.json, per-API: https://eps.eko.in/agent/api/<slug>.json). OpenAPI: https://eps.eko.in/openapi.json.

## Multi-step recipes

### DMT (Fino) — Send Money

Full Fino DMT money-transfer flow: look up the sender, onboard and biometric-eKYC them if new, pick or add the recipient, then send an OTP-verified transfer.

1. `dmt-get-sender` — Check whether the customer is already a registered DMT sender, and which stage of onboarding they are at. The `response_type_id` decides where the flow enters. (if response_type_id 308 → dmt-onboard-sender) (if response_type_id 2134 → dmt-fino-sender-ekyc) (if response_type_id 2129 → dmt-fino-validate-ekyc-otp) (if response_type_id 309 → dmt-get-recipients)
2. `dmt-onboard-sender` — Register a new sender with name, date of birth and residence address. This opens the sender on Eko but leaves KYC pending on Fino (`response_type_id=2134`) — they cannot transact yet. (if response_type_id 309 → dmt-get-recipients)
3. `dmt-fino-sender-ekyc` — Biometric Aadhaar eKYC — one-time per sender. Capture the PID block from an RD-service fingerprint scanner and submit it with the sender's Aadhaar number; the response returns the `kyc_request_id` and `otp_ref_id` the next step needs. Completing eKYC raises the sender's monthly limit from ₹5,000 to ₹25,000.
4. `dmt-fino-validate-ekyc-otp` — Confirm the eKYC by submitting the OTP sent to the sender's Aadhaar-linked mobile, along with the `kyc_request_id` and `otp_ref_id` from the biometric step. The sender is fully KYC-verified on success.
5. `dmt-get-recipients` — List the sender's saved beneficiaries. If the one they want is already there, reuse its `recipient_id` and skip Add Recipient. (if response_type_id 22 → dmt-add-recipient) (if response_type_id 23 → dmt-send-otp)
6. `dmt-add-recipient` — Add the beneficiary the sender wants to transfer to; returns the `recipient_id` used by the two transaction steps.
7. `dmt-send-otp` — Pre-authorise the transfer: sends an OTP to the sender's registered mobile and returns the `otp_ref_id`. Required before every transfer — request a fresh one per attempt.
8. `dmt-initiate-transfer` — Submit the transfer with the customer-entered OTP, its `otp_ref_id`, and a `client_ref_id` unique to this attempt. The only money-debit step — persist `tid` and `bank_ref_num` and reconcile before any retry. (if status 0 → done)

### AePS (Fingpay) — Cash Withdrawal

Aadhaar-enabled cash withdrawal: one-time agent activation and eKYC, daily KYC, then the biometric withdrawal.

1. `activate-aeps-fingpay` — One-time activation of AePS Fingpay for the agent.
2. `aeps-fingpay-send-otp-kyc` — One-time eKYC step 1 (agent onboarding, not per transaction): OTP to the agent's Aadhaar-linked mobile.
3. `aeps-fingpay-verify-otp-kyc` — One-time eKYC step 2 (agent onboarding): verify the OTP with the otp_ref_id and reference_tid from step 1.
4. `aeps-fingpay-biometric-ekyc` — One-time eKYC step 3 (agent onboarding): the agent's biometric PID completes eKYC.
5. `aeps-fingpay-daily-auth` — Daily KYC — biometric-only, repeated once per calendar day before the agent's first transaction.
6. `aeps-fingpay-cash-withdrawal` — Perform the biometric Aadhaar-enabled cash withdrawal. (if status 0 → done)

### BBPS — Pay a Utility Bill

Pick a biller by category, read the fields it requires, fetch the live bill, then pay the exact amount. Get Locations is an optional extra filter on the biller list, and UPPCL (operator 190) additionally needs a district_discome from Get District Discome — neither is a step here because neither applies to every biller.

1. `bbps-get-categories` — List the biller categories and let the agent pick one. The `operator_category_id` chosen here filters the biller list, and is also the `category` param on Fetch Bill and Pay Bill. Do not hard-code these ids — the live list is authoritative. (if response_type_id 2457 → bbps-get-operators)
2. `bbps-get-operators` — List the billers, filtered by the chosen `category` (and optionally by `location` from Get Locations). Note the rename: the `operator_id` returned here is sent as `phone_operator_code` to Fetch Bill and Pay Bill. (if response_type_id 2461 → bbps-get-operator-parameters)
3. `bbps-get-operator-parameters` — Read the fields this operator requires and render the bill-entry form from them. `list_elements` is the source of truth: every `param_name` it returns must be sent to BOTH the next step and Pay Bill, with identical values. For operator 190 (UPPCL) only, also resolve `district_discome` via Get District Discome before continuing.
4. `bbps-fetch-bill` — Fetch the live bill and show the customer the amount and due date. Carry `amount` and `utilitycustomername` into the payment, and reuse this call's `client_ref_id` for it. `response_status_id` is `-1` on success here — branch on `response_type_id`, not on it. On `1468` the bill could not be fetched: verify the account details, retry later, and do not pay. (if response_type_id 1052 → bbps-pay-bill)
5. `bbps-pay-bill` — Pay the exact amount returned by Fetch Bill, echoing back `utilitycustomername`. The only money-debit step — persist `tid` and your `client_ref_id` before any retry. A `208` means the amount did not match: re-fetch the bill and retry with a FRESH `client_ref_id` (one reference identifies one payment attempt and must never be reused across retries); a `tid` is returned even on `208`, so store it first. (if status 0 → done) (if response_type_id 208 → bbps-fetch-bill)
6. `transaction-inquiry` — Reconciliation only, not a mandatory leg — the previous step already completes the flow on success. This is the generic Transaction Inquiry endpoint, shared across every product. Use it when the Pay Bill response timed out or came back awaited: inquire by `tid`, or by your `client_ref_id` if you never received the `tid`. A timeout is never an automatic failure. (if status 0 → done)

### BBPS — Prepaid Mobile / DTH Recharge

Detect the operator and circle from the customer's mobile number, read the operator's input fields, list the available plans, then submit the chosen plan as a payment.

1. `bbps-operator-code-circle` — Detect the telecom operator and circle from the customer's mobile number. Both come back as name/value pairs under `dependent_params` at the top level of the response, not under `data`.
2. `bbps-get-operator-parameters` — Read the recharge fields this operator requires, using the `phone_operator_code` from the previous step as `operator_id`. Prepaid operators typically expose `utility_acc_no` labelled "Mobile Number" plus a "Recharge Type" list — send every returned `param_name` to the payment step.
3. `bbps-recharge-plans` — List the plans for this operator and circle, and let the customer choose one. Mind the rename: pass the previous `circle_area` value as `circleid` here. Plans arrive under `dependent_params` → the `req_list` entry's `value` array. (if response_type_id 1805 → bbps-pay-bill)
4. `bbps-pay-bill` — Submit the recharge. Map the fields: `phone_operator_code` from step 1, `utility_acc_no` = the customer's mobile number, `category` = the Mobile Prepaid / DTH id from Get Categories, and `amount` = the chosen plan's `amount` (or the agent-entered amount when plans were unavailable). `confirmation_mobile_no` and `sender_name` come from agent-entered customer detail. Omit `utilitycustomername` — it is optional, and only applies to bill payments where Bill Fetch supplied it. Persist `tid` and `client_ref_id`. (if status 0 → done)

## Local development & testing (offline mock server)

Test EPS integrations without touching the live API. The mock server replays golden sample responses over plain HTTP on `http://localhost:4010`:

```bash
npx -y @ekoindia/eps-mock-server
```

It mirrors the real EPS paths, so point your EPS base URL at `http://localhost:4010` — no other code change needed. It does not require valid EPS credentials, but keep the same request shape and headers your integration sends. To exercise a documented error branch, append `?eps_scenario=<response_status_id>` to the request for endpoints whose fixture includes that code — e.g. calling the DMT sender lookup (`dmt-get-sender`) with `?eps_scenario=463` returns its documented "sender not found" example. Note the mock selects a scenario by `response_status_id`, which is not the field you branch on: that same example carries `response_type_id` 308, and it is 308 the recipe routes on.

## Live context via MCP

Install the local context server for richer, on-demand lookups:

```bash
npx -y @ekoindia/eps-context-mcp@latest
```
