guide
AEPS Integration Guide
This guide takes you from a new agent to a first cash withdrawal. Read it once, then use the endpoint pages for the exact fields.
1. Before you start
- Your developer account must have AEPS enabled.
- Log in with your client ID and API secret (see Authentication) and send
Authorization: Bearer {token}on every call. - Always send
Accept: application/jsonandContent-Type: application/json. - Real money moves on Production. Test cash withdrawals with a small amount such as Rs 100.
2. Headers and rules on every call
| Rule | Detail |
|---|---|
X-Timestamp header |
Current India time (IST) as 2026-10-14 14:05:30 or 2026-10-14T14:05:30. No time zone suffix. It must be within 15 seconds of our server time, so generate it on every request. |
| IP whitelist | Calls must come from an IP address you whitelisted on your API key. |
reference_id |
Your own unique ID per request. Letters, digits, _ and - only, max 40 characters. Never reuse one. |
| Location | latitude and longitude of the agent, exactly 4 decimal places, inside India. Send the real location. Do not hardcode it. |
ip_address |
Public IPv4 address of the agent device. |
channel, device_id, user_agent |
APP with the Android ID, or WEB with Browser. |
3. The full flow
- Onboard Agent (
POST /api/v1/aeps/agents) — once per agent. Theagent_codeis yours and must be new. - Agent Status (
GET /api/v1/aeps/agents/{agent_code}) — checkkyc_required,daily_2fa_requiredandotp_amount. - Agent KYC — once, only when
kyc_requiredistrue. Uses the agent's own finger. - Daily 2FA — once per day, only when
daily_2fa_requiredistrue. Uses the agent's finger. It has a small charge. - List Banks (
GET /api/v1/aeps/banks) — pick the customer'sbank_iin. - Generate OTP — only for a cash withdrawal at or above
otp_amount. - Transaction —
tran_typeisCW(cash withdrawal),BE(balance) orMS(mini statement). Uses the customer's finger. - Transaction Status — use it after a
202 pendinganswer or a timeout.
4. Capturing the fingerprint (PID data)
pid_data is the PID XML that a registered RD service device returns after a capture, encoded as base64.
- Your app asks the RD service to capture a fingerprint with PID options.
- The device returns an XML starting with
<PidData>. - Check that the response has
errCode="0". Any other code means the capture failed. Capture again. - Base64-encode the complete XML and send it as
pid_data. Do not change it. - Send
bio_typeas0for fingerprint,1for face,2for iris.
Rules for the wadh value in the PID options:
| Call | wadh |
|---|---|
| Agent KYC | Use the kyc_wadh value from Agent Status that matches the bio_type |
| Daily 2FA | Empty |
| Transaction (CW, BE, MS) | Empty |
Never store pid_data or log it. Each capture works for one request only.
5. Transaction answers
200withdata.status = "success"— safe to hand over cash forCW.200withdata.status = "failed"— the bank refused. Show the message. Do not hand over cash.202withdata.status = "pending"— the bank has not answered. Do not hand over cash and do not send again with a newreference_id. Poll Transaction Status.BEandMS:amountisnull. The balance is incustomer_balanceas a plain number such as3345.01. A mini statement is inmini_statement.- Customer Aadhaar numbers are masked in every answer.
- A cash withdrawal is added to your payout wallet at the next settlement time (11:00, 15:00 or 20:00 IST).
settlement_statusandrelease_due_atshow where it is.
6. Common errors
| Code | Meaning | What to do |
|---|---|---|
400 X-Timestamp... |
Missing, wrong format or more than 15 seconds off | Generate a fresh timestamp per call |
400 coordinates must be within India |
Location is outside India | Send the real location |
| 401 | Token missing or not valid | Log in again |
409 kyc_required |
Agent KYC not done | Run Agent KYC |
409 daily_2fa_required |
No Daily 2FA today | Run Daily 2FA |
409 duplicate_reference_id |
reference_id already used |
Send a new one |
422 provider_rejected |
The bank network said no. The message says why. |
See below |
422 amount_out_of_range |
Outside Rs 100 to Rs 10000 | Change the amount |
502 provider_unavailable |
The provider did not answer | Wait, then send with a new reference_id. For a transaction, check Transaction Status first. |
Messages inside provider_rejected:
Unable to process request.— the fingerprint did not match or the capture was poor. Check that the right person gave the finger, the wadh is correct, and the Aadhaar number is right. Capture again.- Validation messages (for example on onboarding) — a field is wrong. Read the message and fix that field.
7. Test it with cURL
Mini statement:
curl -X POST "$BASE_URL/api/v1/aeps/transactions" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Timestamp: $(TZ=Asia/Kolkata date '+%Y-%m-%d %H:%M:%S')" \
-d '{
"agent_code": "AC12345678",
"reference_id": "MS'$(date +%s)'",
"tran_type": "MS",
"amount": null,
"bank_iin": "608087",
"customer_mobile": "9876543210",
"customer_aadhaar": "123456789012",
"otp_reference": null,
"bio_type": "0",
"pid_data": "BASE64_ENCODED_PID_XML",
"channel": "WEB",
"device_id": "Browser",
"ip_address": "49.47.133.99",
"user_agent": "Mozilla/5.0",
"latitude": "25.5899",
"longitude": "85.1376"
}'
For a cash withdrawal use "tran_type": "CW" and "amount": 100.
8. Go-live checklist
- Timestamp is generated per request in IST.
- Your server IP is whitelisted.
- Location is live, not hardcoded.
- You never hand over cash on
pendingorfailed. - You never reuse a
reference_id. - PID data and Aadhaar numbers are not logged or stored.