Digital Payment Integration Guidelines - India
Unify Core — Digital Payment API v2 is a service that enables merchants to accept digital payments through e-wallets in India — both one-time and recurring payments — including refunds and the full periodic billing cycle.
All endpoints (except Get Token and the callback endpoints) require two things in the header: the Authorization: Bearer {token} and the apikey.
Important notes:
apikey + channel + service combination; use the same channel & service on subsequent endpoints.Authorization: Bearer {token} and apikey.apikey is still read from the header by the middleware, even though it is commonly included in the query as well.{ } must be replaced with actual values when making the call.apikey and client secret are confidential — do not share them with unauthorized parties.This is the supported Digital Payment can used in India
| No. | Digital Payment | Category | Method | Code | Status |
|---|---|---|---|---|---|
| 1 | UPI | E-Wallet | EWALLET | UPI | Available |
| 2 | PhonePe | E-Wallet | EWALLET | PHONEPE | Available |
| 3 | GooglePay | E-Wallet | EWALLET | GOOGLEPAY | Available |
| 4 | Paytm | E-Wallet | EWALLET | PAYTM | Available |
Below are the base URLs for each environment.
| Environment | Base URL |
|---|---|
| Sandbox | https://stagingapi.airpay.mobi/ |
| Production | https://api.airpay.mobi/ |
Before calling the Digital Payment API, merchant must obtain an Auth Token first.
Basic Auth (Get Token only) — the Get Token endpoint uses HTTP Basic Auth, where the username is the client id and the password is the client secret, sent as header Authorization: Basic {basicAuth}.
Bearer Token + apikey (all other endpoints) — the token from Get Token is used on all subsequent request endpoints, together with the apikey header:
Authorization: Bearer {token}
apikey: {apiKey}
The token is scoped to the apikey + channel + service combination. A token obtained for one channel/service is not valid for another combination — make sure the channel & service in the path of subsequent endpoints exactly match the ones used when running Get Token.
Obtain a token using client id & client secret. In Postman the token is automatically saved to the token variable via a test script, then used on the subsequent endpoints.
Sample request:
https://api.airpay.mobi/api/v2/ext/ID/OVO/PULSA/2611263d-2406-489c-9042-abcsd76f9b/token/
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| apiKey required | string <= 150 characters Merchant API key |
curl --request GET \ --url {domain}/api/v2/ext/{country}/{channel}/{service}/{apiKey}/token/ \ --header 'accept: application/json' \ --user 'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET'
{- "code": "200",
- "message": "Success",
- "data": {
- "token": "fcf33833-a4d1-4fb1-a55e-b2023031ed99"
}
}Once the recurring payment is registered, the following sequence forms one recurring billing cycle:
IMPORTANT: Always check the Mandate Status before running Trigger Charge Recurring. A predebit that has been sent does not guarantee the mandate is still active on the debit day.
One-time e-wallet payment. The customer pays a certain amount through an e-wallet for a single transaction, with no follow-up billing.
Result: an e-wallet payment transaction is created. The final status is delivered via the Ewallet Callback (POST {domain}/api/v2/ext/ewallet/callback, sent by PayU).
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| msisdn required | string <= 50 characters Customer phone number, example: 628123456789 |
| amount required | string <= 50 characters Payment / debit / refund amount |
| order_number required | string <= 100 characters Merchant order number, example: ORD-20260627-001 |
| trxid required | string <= 150 characters Merchant/related transaction ID, example: TRX20260627001 |
| currency required | string <= 10 characters Currency, example: IDR |
| cycle | string <= 50 characters Billing cycle, example: daily / ADHOC |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success",
- "data": {
- "trxid": "LINKIT25061750660948",
- "trx_date": "2026-06-23 06:42:27 UTC",
}
}POST alternative for the one-time e-wallet payment request, using a JSON body.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
| name | string <= 50 characters User name |
string <= 50 characters User email | |
| msisdn required | string <= 50 characters Customer phone number |
| amount required | number Payment amount |
| description | string <= 100 characters Payment description |
| currency required | string <= 10 characters Currency |
| return_url | string The return url after success payment |
| payment_method | string <= 50 characters Payment method |
| order_number required | string <= 50 characters Merchant order number |
| trxid required | string <= 50 characters Merchant transaction ID |
{- "name": "John Doe",
- "email": "john@example.com",
- "msisdn": "628123456789",
- "amount": 50000,
- "description": "Payment for service",
- "currency": "IDR",
- "payment_method": "ewallet",
- "order_number": "ORD-20260627-001",
- "trxid": "TRX20260627001"
}{- "code": 200,
- "message": "success",
- "data": {
- "trxid": "LINKIT25061750660948",
- "trx_date": "2026-06-23 06:42:27 UTC",
}
}Recurring payment request. The customer gives consent (a mandate) allowing their balance to be debited periodically according to an agreed cycle.
Result: the recurring payment mandate/schedule is created. The status is delivered via the Payin Recurring Callback (POST {domain}/api/v2/ext/payin-recurring/callback).
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| amount required | string <= 50 characters Payment / debit / refund amount |
| msisdn required | string <= 50 characters Customer phone number, example: 628123456789 |
| order_number required | string <= 100 characters Merchant order number, example: ORD-20260627-001 |
| currency | string <= 10 characters Currency, example: INR / IDR |
| cycle | string <= 50 characters Billing cycle, example: daily / ADHOC |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success"
}POST alternative for the recurring payment request, using a JSON body.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
| amount required | number Recurring payment amount |
| msisdn required | string Customer phone number |
string User email | |
| order_number required | string Merchant order number |
| country | string Country code |
| currency | string Currency, example: INR / IDR |
| return_url | string The return url after success payment |
| payment_method | string |
| channel_code | string |
| callback_url | string |
| interval | string |
| cycle | string Billing cycle, example: ADHOC |
| payment_start_date | string <date> |
| payment_end_date | string <date> |
| is_no_expired | string |
{- "amount": 5,
- "msisdn": "919979092377",
- "email": "user@example.com",
- "order_number": "1233213222613",
- "country": "IN",
- "currency": "INR",
- "payment_method": "UPI",
- "channel_code": "googlepay",
- "interval": "1",
- "cycle": "ADHOC",
- "payment_start_date": "2026-07-02",
- "payment_end_date": "2026-07-15",
- "is_no_expired": "false"
}{- "code": 200,
- "message": "success"
}Refund request. The return of funds from a previously successful transaction, either partially or in full.
Result: the refund request is forwarded to the payment gateway. The final status is delivered via the Refund Callback (POST {domain}/api/v2/ext/refund/callback), example status: REFUND_SUCCESS.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| txnid required | string <= 150 characters ID of the transaction to be refunded |
| refund_id required | string <= 100 characters Merchant refund ID, example: RFD-20260627-001 |
| amount required | string <= 50 characters Payment / debit / refund amount |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success"
}POST alternative for the refund request, using a JSON body.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
| auth_payu_id required | string Authorization ID from the payment gateway (PayU) |
| refund_id required | string Merchant refund ID, example: RFD-20260627-001 |
| amount required | number Amount to be refunded |
| transaction_id required | string ID of the transaction to be refunded |
{- "auth_payu_id": "29139358992",
- "refund_id": "REFUND-2024011623-001",
- "amount": 50,
- "transaction_id": "trigger_d144b8dd_1783254835"
}{- "code": 200,
- "message": "success"
}Pre-debit notification to the customer. Predebit is sent one day before the debit (D-1) to inform the customer that their balance will be debited on a specific date.
Result: the pre-debit notification is sent to the customer. Confirmation is delivered via the Predebit Callback (POST {domain}/api/v2/ext/predebit/callback).
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| auth_payu_id required | string <= 100 characters Authorization ID from the payment gateway (PayU) |
| request_id required | string <= 150 characters Unique request ID (UUID) / charge request ID |
| amount required | string <= 50 characters Payment / debit / refund amount |
| debit_date required | string <date> <= 20 characters Debit date, format YYYY-MM-DD |
| invoice_display_number required | string <= 100 characters Invoice number displayed to the customer |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success"
}Check the mandate status before executing the debit. Between the predebit (D-1) and the debit (D), the customer may unsubscribe. Therefore the mandate status must be checked before the charge is triggered.
Result: returns the customer mandate status (active / inactive), which determines whether the debit may proceed.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| auth_payu_id required | string <= 100 characters Authorization ID from the payment gateway (PayU) |
| request_id required | string <= 150 characters Unique request ID (UUID) / charge request ID |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success",
- "data": {
- "mandate_status": "active"
}
}Execute the customer balance debit (recurring). The execution of the customer balance debit for the current billing cycle.
Result: the customer balance is debited by the specified amount. The final result is delivered via the Trigger Charge Recurring Callback (POST {domain}/api/v2/ext/trigger-charge-recurring/callback).
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| auth_payu_id required | string <= 100 characters Authorization ID from the payment gateway (PayU) |
| request_id required | string <= 150 characters Unique request ID (UUID) / charge request ID |
| amount required | string <= 50 characters Payment / debit / refund amount |
| phone required | string <= 50 characters Customer phone number |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
{- "code": 200,
- "message": "success"
}POST alternative for the trigger charge recurring request, using a JSON body.
| country required | string <= 50 characters Country code in the path, example: ID |
| channel required | string <= 50 characters Channel code, example: OVO. Must match the one used when obtaining the token. |
| service required | string <= 50 characters Service code, example: PULSA. Must match the one used when obtaining the token. |
| apikey required | string <= 50 characters Merchant API key (still required in the header, even for GET requests) |
| Authorization required | string Example: Bearer YOUR_TOKEN Bearer access token obtained from the Get Token endpoint |
| auth_payu_id required | string Authorization ID from the payment gateway |
| request_id required | string Charge request ID, example: trigger_LINKIT12398761 |
| amount required | string Amount debited, example: 5.00 |
| phone required | string Customer phone number |
string | |
| currency | string |
| description | string |
| callback_url | string |
| country | string |
{- "auth_payu_id": "28657904858",
- "request_id": "trigger_LINKIT12398761",
- "amount": "5.00",
- "phone": "081292795541",
- "email": "user@example.com",
- "currency": "INR",
- "description": "Weekly subscription",
- "country": "{country}"
}{- "code": 200,
- "message": "success"
}Callback endpoints receive notifications from the payment gateway (PayU). Callbacks do not require a Bearer Token.
Callbacks from PayU (ewallet, refund, trigger charge) are flat and do not include apikey/channel/service in the body. If trx_id is empty, the system falls back to looking up the transaction via reference_id / txn_id.
Charge result notification (delivery notification). Informs the merchant system of the debit/charge result.
| apikey required | string <= 150 characters Merchant API key |
| country required | string <= 50 characters Country code |
| channel required | string <= 50 characters Channel code |
| service required | string <= 50 characters Service code |
| trxid required | string <= 150 characters Merchant/related transaction ID, example: TRX20260627001 |
| status_code required | string <= 50 characters Status code, example: success |
| status_desc required | string <= 150 characters Status description, example: charge notification received |
{- "code": 200,
- "message": "success"
}POST variant of the charge result notification (delivery notification).
| apikey required | string <= 150 characters Merchant API key |
| country required | string <= 50 characters Country code |
| channel required | string <= 50 characters Channel code |
| service required | string <= 50 characters Service code |
| trxid required | string <= 150 characters Merchant/related transaction ID, example: TRX20260627001 |
| status_code required | string <= 50 characters Status code, example: success |
| status_desc required | string <= 150 characters Status description, example: charge notification received |
{- "code": 200,
- "message": "success"
}Sent by PayU with the final status of a one-time e-wallet payment. Flat body, does not include apikey/channel/service.
| property name* additional property | any |
{ }{- "code": 200,
- "message": "success"
}Sent by PayU with the final status of a refund request (example status: REFUND_SUCCESS). Flat body, does not include apikey/channel/service.
| property name* additional property | any |
{ }{- "code": 200,
- "message": "success"
}Confirmation callback for the predebit (D-1) notification.
| property name* additional property | any |
{ }{- "code": 200,
- "message": "success"
}Delivers the status of the recurring payment mandate/schedule registration (Notification Initiate Payment / MO).
| property name* additional property | any |
{ }{- "code": 200,
- "message": "success"
}Sent by PayU with the final result of the recurring balance debit. Flat body, does not include apikey/channel/service.
| property name* additional property | any |
{ }{- "code": 200,
- "message": "success"
}