POSTAePS Cash Withdrawal
Withdraw cash from any Aadhaar-linked bank account using biometric fingerprint authentication — no card or PIN required.
- Moves money: Moves real money and cannot be undone. After a timeout, confirm the outcome before ever re-sending.
- Earns commission: You earn 0.40% up to ₹3,000; ₹13 flat for ₹3,001–₹10,000 per withdrawal.
Lets a customer withdraw cash from any Aadhaar-linked bank account using a live fingerprint scan — no card or PIN. The agent's biometric device produces a PID XML blob that is forwarded verbatim, and the customer's Aadhaar number is RSA-encrypted before transmission.
Encrypt the customer's Aadhaar with Fingpay's RSA public key (PKCS#1 v1.5
padding) and Base64-encode it before sending it as aadhar. See the
Aadhaar Encryption (Fingpay AePS) guide
for how to get the key and code samples.
Prerequisites
The agent must have completed, in order:
- AePS Fingpay activation
- One-time eKYC (Send OTP → Verify OTP → Biometric eKYC)
- Daily KYC for the current day
Due to NPCI compliance, the agent's Daily KYC must succeed for the current calendar day before any cash-withdrawal is attempted.
Amounts above ₹5,000 — transaction OTP
Fingpay requires a fresh, transaction-scoped OTP for every withdrawal above ₹5,000. For ₹5,000 or less there is no OTP step — skip this section.
- Call Cash Withdrawal OTP with the
same
aadhar,bank_code,latlongandamount. It returnsdata.fp_transaction_id, and the customer receives a 6-digit OTP by SMS on their Aadhaar-linked mobile. - Put that SMS OTP in the
otpattribute of thePidOptionsyou send to the RD-service device, then capture the customer's fingerprint. - Call Cash Withdrawal with the resulting
piddata, plustxn_otp_request_idset to thefp_transaction_idfrom step 1.
txn_otp_request_id and the otp inside PidOptions are two different values,
and both are required: the first is the fp_transaction_id reference, the
second is the 6-digit OTP from the customer's SMS.
<PidOptions ver="1.0"><Opts fCount="1" fType="2" format="0" pidVer="2.0" timeout="30000"otp="123456" posh="UNKNOWN" env="P" /></PidOptions>
An fp_transaction_id belongs to one withdrawal attempt — generate a new one,
and capture again, for every attempt. Never reuse it.
If you skip the OTP call for an amount above ₹5,000, Cash Withdrawal does
not withdraw anything. It generates the OTP itself and returns
response_type_id 1459 with data.fp_transaction_id instead of a
transaction result. Always call Cash Withdrawal OTP explicitly. If you do get
1459, recover by capturing the fingerprint with the OTP the customer just
received and calling Cash Withdrawal again with that fp_transaction_id —
do not generate another OTP.
An expired, invalid or already-used OTP has no error code of its own — it
returns the generic 1464 Transaction Fail. Once a failure is final,
generate a fresh OTP and capture again before retrying. A 1465 Pending, a
timeout or a dropped connection is not a failure: reconcile via
Transaction Inquiry before any retry, to avoid a
double debit.
Aadhaar encryption
Encrypt the Aadhaar number before sending it (the same scheme used by all AePS transaction APIs):
- Base64-decode the public key.
- RSA-encrypt the Aadhaar number with the decoded key.
- Base64-encode the result and send that as the
aadharparameter.
Fingpay has no UAT environment, so there is no UAT key. The production public key is in Console → Credentials once your account is active.
Biometric (PID) capture
New to RDService? The
Aadhaar Biometric Authentication guide
covers the full capture flow — driver discovery, PidOptions, error codes —
for Web and Android, and includes an in-browser device tester.
The PidData XML from the RD-service device must use:
Data type="X"(XML), base64-encoded- a
DeviceInfomcvalue carrying the device public-key certificate signed by the Device Provider Key - fingerprint quality of at least 35
nmPoints
Per NPCI's FIR-FMR single-PID-block guidance, capture fingerprints with
fType = 2 (not 0). A subset of banks that have not yet completed
FMR+FIR compliance still require fType = 0 — check the current bank list
before going live.
- AePS (Fingpay) — Cash Withdrawal — Aadhaar-enabled cash withdrawal: one-time agent activation and eKYC, daily KYC, a transaction OTP for amounts above ₹5,000, then the biometric withdrawal.
Request
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
customer_id | string | required | Customer's registered mobile number.e.g. 9000000000 |
customer_idstringRequiredCustomer's registered mobile number.
example: 9000000000
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
initiator_id | string | required | Registered mobile number of the API user (see Platform Credentials).e.g. 9962981729 |
client_ref_id | string | optional | Unique reference ID per API call, generated by your system (10–20 characters; 10 recommended). The SDKs generate one for every non-GET call when you don't.e.g. 2026010100123456789 |
user_code | string | required | Unique code of your user/agent/retailer the service is run for. Use `Onboard Agent` API to register your userse.g. 10000001 |
bank_code | string | required | Short bank code identifying the customer's Aadhaar-linked bank (e.g. `HDFC`, `SBIN`). Obtain from the bank list API.e.g. HDFC |
aadhar | string | required | RSA-encrypted (PKCS#1 v1.5), Base64-encoded Aadhaar number of the customer. See the Aadhaar Encryption (Fingpay AePS) guide for the key and code samples.e.g. BASE64_ENCRYPTED_AADHAAR |
latlong | string | required | GPS coordinates of the transaction origin in 'latitude,longitude' format.e.g. 28.6139,77.2090 |
piddata | string | required | PID data captured from the UIDAI-certified biometric device, as a raw XML string. Must use Data type='X' (XML, not Protobuf). DeviceInfo must include the 'mc' (device certificate) parameter. fType must be 2. For an `amount` above ₹5,000, set the `otp` attribute of the PidOptions `<Opts>` element to the customer's 6-digit SMS OTP before capture — the OTP itself, not the `fp_transaction_id`.e.g. <?xml version='1.0'?><PidData><Data type='X'>...</Data><DeviceInfo mc='...' /></PidData> |
amount | number | required | Withdrawal amount in Indian Rupees (integer). Must be greater than 0 for cash withdrawal. Above ₹5,000, call Cash Withdrawal OTP first and send `txn_otp_request_id`.e.g. 1000 |
txn_otp_request_id | string | optional | Required when `amount` is above ₹5,000: the `fp_transaction_id` returned by Cash Withdrawal OTP for this attempt (e.g. `FP2609010001234567`). Omit for ₹5,000 or less. |
initiator_idstringRequiredRegistered mobile number of the API user (see Platform Credentials).
example: 9962981729
client_ref_idstringoptionalUnique reference ID per API call, generated by your system (10–20 characters; 10 recommended). The SDKs generate one for every non-GET call when you don't.
example: 2026010100123456789
user_codestringRequiredUnique code of your user/agent/retailer the service is run for. Use `Onboard Agent` API to register your users
example: 10000001
bank_codestringRequiredShort bank code identifying the customer's Aadhaar-linked bank (e.g. `HDFC`, `SBIN`). Obtain from the bank list API.
example: HDFC
aadharstringRequiredRSA-encrypted (PKCS#1 v1.5), Base64-encoded Aadhaar number of the customer. See the Aadhaar Encryption (Fingpay AePS) guide for the key and code samples.
example: BASE64_ENCRYPTED_AADHAAR
latlongstringRequiredGPS coordinates of the transaction origin in 'latitude,longitude' format.
example: 28.6139,77.2090
piddatastringRequiredPID data captured from the UIDAI-certified biometric device, as a raw XML string. Must use Data type='X' (XML, not Protobuf). DeviceInfo must include the 'mc' (device certificate) parameter. fType must be 2. For an `amount` above ₹5,000, set the `otp` attribute of the PidOptions `<Opts>` element to the customer's 6-digit SMS OTP before capture — the OTP itself, not the `fp_transaction_id`.
example: <?xml version='1.0'?><PidData><Data type='X'>...</Data><DeviceInfo mc='...' /></PidData>
amountnumberRequiredWithdrawal amount in Indian Rupees (integer). Must be greater than 0 for cash withdrawal. Above ₹5,000, call Cash Withdrawal OTP first and send `txn_otp_request_id`.
example: 1000
txn_otp_request_idstringoptionalRequired when `amount` is above ₹5,000: the `fp_transaction_id` returned by Cash Withdrawal OTP for this attempt (e.g. `FP2609010001234567`). Omit for ₹5,000 or less.
These headers authenticate and sign every request. See How Auth Works for details.
| Field | Type | Required | Description |
|---|---|---|---|
developer_key | string | required | Static API key issued to your account after KYC. |
secret-key | string | required | Dynamic per-request signature: base64(HMAC-SHA256(timestamp, base64(access_key))). |
secret-key-timestamp | string | required | Current time in milliseconds since UNIX epoch, used to compute secret-key. Must match server time. |
content-type | string | required | application/jsone.g. application/json |
developer_keystringRequiredStatic API key issued to your account after KYC.
secret-keystringRequiredDynamic per-request signature: base64(HMAC-SHA256(timestamp, base64(access_key))).
secret-key-timestampstringRequiredCurrent time in milliseconds since UNIX epoch, used to compute secret-key. Must match server time.
content-typestringRequiredapplication/json
example: application/json
Response types
| response_type_id | Meaning | Next step |
|---|---|---|
1463 | Transaction Successful | — |
1464 | Transaction Fail — above ₹5,000 this also covers an expired, invalid or already-used OTP (there is no separate code). Once the failure is final, generate a fresh OTP and re-capture before retrying | — |
1465 | Transaction Pending — check final status later | Transaction Inquiry |
1459 | OTP required — `amount` is above ₹5,000 but no `txn_otp_request_id` was sent. Nothing was withdrawn; an OTP was sent to the customer. Retry with `data.fp_transaction_id` as `txn_otp_request_id` and the customer's SMS OTP in the PidOptions `otp` attribute — do not generate another OTP | — |
Responses
1463Transaction Successful
statusnumberPrimary success indicator (0 = success).
messagestringHuman-readable response / error message.
response_status_idnumberUI display hint only (-1/0 success, 1 failure, 2 initiated, 3 refund initiated, 4 refunded). Never branch on it — use `status` (and `tx_status` for financial APIs), or `response_type_id` where documented.
response_type_idnumberA unique id for every possible response shape (success or error) — useful for client logic branching and analytics.
tx_statusstringTransaction state: 0=Success, 1=Fail, 2=Initiated / Response Awaited (NEFT) — poll Transaction Inquiry, 3=Refund Pending, 4=Refunded, 6=Response Awaited — Transaction Inquiry required.
txstatus_descstringHuman-readable transaction status.
dataobjectAPI-specific response payload.
tidstringEko's internal transaction ID. Use for reconciliation and support queries.
amountstringWithdrawal amount processed in the transaction (INR).
bankstringName of the customer's bank where the debit occurred.
bank_ref_numstringBank/NPCI reference number (RRN) for the transaction. Empty on failure.
balancestringRemaining balance in the customer's bank account after withdrawal, if returned by the bank.
customer_balancestringCustomer's account balance as reported by the bank. Empty when not returned.
tdsstringTax deducted at source on the agent's commission (INR).
commissionstringCommission earned by the agent on this transaction (INR).
feestringFee charged for the transaction (INR). May be empty.
service_taxstringService tax component on the fee (INR). May be empty.
totalfeestringTotal fee including taxes (INR). May be empty.
shopstringAgent's shop/merchant name.
shop_address_line1stringAgent's shop address. May be empty.
sender_namestringName of the agent/sender initiating the transaction.
merchantnamestringRegistered merchant name of the agent.
merchant_codestringMerchant code of the agent. May be empty.
user_codestringEcho of the agent's user_code from the request.
aadharstringMasked Aadhaar number of the customer.
auth_codestringBank authorization code. May be empty.
stanstringSystem Trace Audit Number assigned by the switch. May be empty.
terminal_idstringTerminal identifier. May be empty.
tx_statusstringTransaction state within the data block: 0=Success, 1=Fail, 2=Pending.
transaction_datestringTransaction date (DD-MM-YY HH:MM:SS).
transaction_timestringTransaction timestamp (DD-MM-YY HH:MM:SS).
reasonstringFailure reason, when the transaction did not complete. Empty on success.
commentstringHuman-readable transaction remark from the provider (e.g. 'Request Completed').
fp_transaction_idstringReturned only with `response_type_id` 1459 (OTP required — nothing was withdrawn): the OTP reference to send back as `txn_otp_request_id`.
Next steps
NextPOSTAePS Balance EnquiryCheck a customer's bank account balance using Aadhaar number and biometric fingerprint — no card or PIN required.Related
- AePS Cashout — details & pricingFeatures, plans and pricing for this product.
- Integrate using AIBuild agent-native integrations with MCP, SDKs and packs.
- Integrate using an SDKNode.js, Python, PHP, Go and Java clients with signing built in.
- Aadhaar Biometric Authentication (RDService) guideHow to capture the PID block from a fingerprint scanner on Web or Android.
- Aadhaar Encryption (Fingpay AePS) guideWhere to get the RSA public key, encryption steps and code samples for the `aadhar` parameter.