Vizo Digital Api
Sign in
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/json and Content-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

  1. Onboard Agent (POST /api/v1/aeps/agents) — once per agent. The agent_code is yours and must be new.
  2. Agent Status (GET /api/v1/aeps/agents/{agent_code}) — check kyc_required, daily_2fa_required and otp_amount.
  3. Agent KYC — once, only when kyc_required is true. Uses the agent's own finger.
  4. Daily 2FA — once per day, only when daily_2fa_required is true. Uses the agent's finger. It has a small charge.
  5. List Banks (GET /api/v1/aeps/banks) — pick the customer's bank_iin.
  6. Generate OTP — only for a cash withdrawal at or above otp_amount.
  7. Transaction — tran_type is CW (cash withdrawal), BE (balance) or MS (mini statement). Uses the customer's finger.
  8. Transaction Status — use it after a 202 pending answer 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.

  1. Your app asks the RD service to capture a fingerprint with PID options.
  2. The device returns an XML starting with <PidData>.
  3. Check that the response has errCode="0". Any other code means the capture failed. Capture again.
  4. Base64-encode the complete XML and send it as pid_data. Do not change it.
  5. Send bio_type as 0 for fingerprint, 1 for face, 2 for 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

  • 200 with data.status = "success" — safe to hand over cash for CW.
  • 200 with data.status = "failed" — the bank refused. Show the message. Do not hand over cash.
  • 202 with data.status = "pending" — the bank has not answered. Do not hand over cash and do not send again with a new reference_id. Poll Transaction Status.
  • BE and MS: amount is null. The balance is in customer_balance as a plain number such as 3345.01. A mini statement is in mini_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_status and release_due_at show 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 pending or failed.
  • You never reuse a reference_id.
  • PID data and Aadhaar numbers are not logged or stored.