Complete outlet KYC, generate a withdrawal QR, and confirm the final UPI ATM transaction status.
Integrate UPI ATM withdrawals through Pay2New: confirm outlet eligibility, complete biometric KYC, generate a QR code, and confirm the final transaction status.
Authentication and outlet eligibility
Every UPI ATM request requires your secret header and the active Pay2New outletId returned after onboarding. Your source IP must be allowlisted, your partner account, KYC, wallet and API access must be active, and UPI ATM service must be enabled.
Connection details
| Setting | Value |
|---|---|
| API base URL | https://pay2new.in/apis/upiAtm/v1 |
| Authentication | secret request header |
| Outlet | outletId request header containing the Pay2New outlet/customer ID |
| JSON requests | Content-Type: application/json |
| JSON responses | Accept: application/json |
Keep credentials on your server. Use the Pay2New outlet ID for this integration.
Integration flow
| Step | Method and endpoint | What to do next |
|---|---|---|
| 1. Check KYC | POST /biometricKycStatus | Read data.status, data.action, data.referenceKey and data.pidOptionWadh. No request body is required. |
| 2. Complete KYC if needed | POST /biometricKyc | Submit the returned reference and fresh registered-device capture. Recheck KYC status. |
| 3. Generate the withdrawal QR | POST /generateQr | Save order_id and display the returned qrString using your QR renderer. |
| 4. Confirm the withdrawal | POST /qrStatus | Send order_id and handle the confirmed success, failure or pending state. |
KYC is complete when data.action is NO-ACTION-REQUIRED and data.status is APPROVED. Otherwise, follow the action and capture information returned by the status request.
See Biometric Kyc Status, Biometric KYC and Generate QR for their complete request and response fields.
Biometric KYC
Customer consent and fresh capture
Obtain the customer's consent before biometric capture. Submit a fresh biometricData JSON object from the registered device, using the capture options returned by the KYC status request. Example values are placeholders and cannot replace an actual device capture.
| Request field | Required | Description |
|---|---|---|
referenceKey | Yes | Reference from the UPI ATM KYC status response. |
latitude | Yes | Decimal latitude of the capture location. |
longitude | Yes | Decimal longitude of the capture location. |
request_id | Yes | Your request reference, at least 8 characters. It is returned as order_id. |
biometricData | Yes | Complete fresh biometric capture as a JSON object. |
biometricData.aadhaar_number | Yes | Customer Aadhaar number, exactly 12 digits. |
Complete sample biometricData
The sample below includes the full biometric field structure. Replace the illustrative customer/device values and encrypted-data placeholders with the values from a fresh registered-device capture. Keep the field names and their case; capture counts and types must match the actual device response.
{
"biometricData": {
"aadhaar_number": "999999999999",
"dc": "SAMPLE_REGISTERED_DEVICE_CODE",
"ci": "20261231",
"hmac": "BASE64_ENCRYPTED_PID_HASH",
"dpId": "SAMPLE_DEVICE_PROVIDER_ID",
"mc": "BASE64_DEVICE_CERTIFICATE",
"pidDataType": "X",
"sessionKey": "BASE64_ENCRYPTED_SESSION_KEY",
"mi": "SAMPLE_DEVICE_MODEL",
"rdsId": "SAMPLE_RD_SERVICE_ID",
"errCode": "0",
"errInfo": "",
"fCount": "1",
"fType": "2",
"iCount": "0",
"iType": "",
"pCount": "0",
"pType": "",
"srno": "SAMPLE_DEVICE_SERIAL_NUMBER",
"sysid": "SAMPLE_SYSTEM_ID",
"ts": "2026-09-26T12:00:00+05:30",
"pidData": "BASE64_ENCRYPTED_PID_DATA",
"qScore": "100",
"nmPoints": "46",
"rdsVer": "SAMPLE_RD_SERVICE_VERSION"
}
}
After submitting KYC, call /biometricKycStatus again to confirm approval before generating a withdrawal QR.
Generate a withdrawal QR
| Request field | Required | Description |
|---|---|---|
amount | Yes | Positive amount in rupees, in multiples of 100. |
latitude | Yes | Decimal transaction latitude. |
longitude | Yes | Decimal transaction longitude. |
customer_mobile | Yes | Customer mobile number, exactly 10 digits. |
request_id | Yes | Your unique request reference, at least 8 characters. |
product_code | Yes | Numeric UPI ATM product code enabled for your account. |
ip | Yes | IPv4 address of the customer-facing endpoint. |
Use the returned qrString to display the QR and retain the Pay2New order_id. The response can also include qrStatus, qrMobile, qrCreatedDate, expiryDt and displayExpirySec. The successful response currently returns displayExpirySec: 60; use the returned expiry and transaction status when handling expiry.
QR creation is not withdrawal confirmation
A status of 1 from generateQr confirms only that the QR was generated. The withdrawal is still pending. Confirm the withdrawal through qrStatus before treating it as complete. Wallet settlement occurs after final status confirmation.
Confirm transaction status
See QR Status for the complete contract and success, failure, pending and lookup-error examples.
Send the saved order ID to POST https://pay2new.in/apis/upiAtm/v1/qrStatus, with the same authentication and outlet headers.
{
"order_id": "ORDER_ID_FROM_GENERATE_QR"
}
JSON status | Meaning for /qrStatus | Integration action |
|---|---|---|
1 | Confirmed success | Mark the withdrawal successful. |
2 | Failed transaction or lookup error | A response with the matching order and transaction fields reports failure. A message-only lookup error does not establish the transaction outcome. |
3 | Pending | Continue checking the existing order. Do not initiate a duplicate withdrawal for the same customer request. |
The response includes order_id, request_id, txn_value, balance and message, with additional reference and customer details when available. An unknown order returns status: 2 and message: "Transaction not found".
Duplicate requests and errors
| Situation | Response or handling |
|---|---|
Repeated generateQr request with the same request_id, amount and mobile | Returns the existing order reference and null QR fields. Continue using the existing order. |
Same request_id with a different amount or mobile | Returns status: 2 with request_id already used for another transaction. |
| Amount is not a positive multiple of 100 | Returns status: 2 with an amount-validation message. |
| Missing or invalid JSON fields | Can return status: 2, message: "Invalid Parameters" and an errors object. |
| Invalid authentication, outlet or disabled service | Can return only status and message. Resolve the reported condition before retrying. |
Read the application status
Use the JSON status and message fields to determine the operation result. HTTP success alone does not confirm a successful transaction, and application errors are not guaranteed to use HTTP 400.
