U UPS Payments
v1 · stable REST · JSON INR

API Reference — Transactions, Payouts & Webhooks

Integration guide for partners using the UPS payments API. Collect payments over UPI, bank transfer or cash, send money out through payouts, and receive a callback for every terminal state change.

Conventions#

Money

All money values are decimal strings in INR — for example "490.00".

Timestamps

Timestamps are ISO-8601 with microseconds and a trailing Z (UTC), e.g. 2026-04-29T14:43:10.245112Z.

Base URL

Replace {{BASE}} with the API base URL given to you during onboarding.

Authentication#

Every request carries one of two headers. Most endpoints use your long-lived company key; the hosted-pay polling endpoint uses the short-lived payment session key returned when a transaction is created.

X-UPS-KEY

Company key · long-lived

Used by 1.1, 1.2, 2.1 and 2.2.

X-UPS-KEY: Api-Key <company key>

X-API-KEY

Payment session key · expires in 10 minutes

Returned as api_key by 1.1 and used only by 1.3.

X-API-KEY: <payment session key>
1

Transactions (collect a payment)#

Collect a payment. Create an intent with initiate_trx, show the customer the QR / intent link or destination account, then learn the outcome by polling the status endpoints or by receiving the transaction webhook.

1.1 Initiate a transaction#

POST /api/transactions/initiate_trx/ Auth · X-UPS-KEY

Create a new payment intent.

Request body

FieldTypeRequiredNotes
amountfloatYesAmount the customer pays.
reference_idstringYesYour idempotency / order id. Echoed back in status responses and webhooks as reference_id.
account_typestringNoUPI (default), RTGS_IMPS_NEFT, or CASH.
sourcestringNoFree-form tag (default "API").
namestringNoEnd-user name (default "API").
redirect_urlstringNoURL the user is sent to after payment.

api_key in the response is the payment session key (X-API-KEY) used by the polling endpoint in §1.3. It expires in 10 minutes.

For account_type=CASH / RTGS_IMPS_NEFT the response also returns account_name, account_number, account_ifsc and bank_name so you can show the destination account to the customer.

Errors

400

Bad Request — no eligible account is currently available, e.g. {"message": "No active account ... please try again later."}

Request body
{
    "amount": 500,
    "reference_id": "ORD-1029",
    "account_type": "UPI",
    "source": "checkout-web",
    "name": "Riya Sharma"
}
Response · 201 Created UPI
{
    "trx_id": 4711,
    "qr_code": "data:image/png;base64,iVBORw0KGgo...",
    "upi_intent": "upi://pay?pa=...",
    "amount": 500,
    "api_key": "9c4e1c2b9d3f8a1e6f02d4c2a7e6c0a3df9b5f17",
    "expires_at": "2026-04-29T14:49:16.000Z",
    "expire_in": 10,
    "auto_approve_enable": true,
    "redirect_url": "{{BASE}}/pay/9c4e1c2b9d3f8a1e6f02d4c2a7e6c0a3df9b5f17"
}

1.2 Transaction status by reference#

GET /api/transactions/{reference_number}/status/ Auth · X-UPS-KEY

Pull the status of a transaction by your reference_id.

Response fields

FieldNotes
idOur transaction id (the trx_id from §1.1).
trx_statusOne of pending approved rejected
is_verifiedWhether the payment was verified against the bank feed.
utrBank UTR for the credit, null until settled.
trx_feesFee deducted, decimal string in INR.
net_amountAmount credited to you after fees.
Request
GET /api/transactions/ORD-1029/status/
X-UPS-KEY: Api-Key <company key>
Response · 200 OK
{
    "status": "success",
    "message": "success",
    "data": {
        "id": 4711,
        "amount": 500.0,
        "is_verified": true,
        "source": "checkout-web",
        "rejected": false,
        "updated_at": "2026-04-29T14:43:10.245112Z",
        "created_at": "2026-04-29T14:39:16.821000Z",
        "reference_id": "ORD-1029",
        "utr": "123456789012",
        "trx_status": "approved",
        "account_type": "UPI",
        "currency": "INR",
        "trx_fees": "10.00",
        "net_amount": "490.00"
    }
}

1.3 Transaction status by trx_id#

POST /api/transactions/trx_status/ Auth · X-API-KEY

Same status payload as §1.2, keyed by trx_id instead of reference id. Used by hosted-pay polling.

This endpoint authenticates with the payment session key (X-API-KEY) from §1.1 — not your company key. The session key expires 10 minutes after the transaction is created.

Request body
{ "trx_id": 4711 }
Response · 200 OK
{ "status": "success" } // or "rejected" or false
2

Payouts (send money out)#

Send money out over UPI, bank transfer or cash. Create the request with initiate_payout_request, then reconcile with the status endpoint or the payout webhook.

2.1 Initiate a payout request#

POST /api/payout-requests/initiate_payout_request/ Auth · X-UPS-KEY

Create a payout request. The required fields depend on requested_type.

IP allowlist. If your account has an IP allowlist configured, this endpoint only accepts requests originating from one of those IP addresses. Requests from any other IP are rejected with 403 Forbidden {"detail": "IP address <ip> is not allowed to access this API."}. Share the static IP(s) of your servers during onboarding. If no allowlist is configured, requests are accepted from any IP.

Common fields

FieldTypeRequiredNotes
requested_typestringYesOne of UPI, RTGS_IMPS, CASH.
amountfloatYesMust be > 0.
first_namestringYesBeneficiary first name.
account_holder_namestringYesBeneficiary full name on the receiving account.
reference_idstringOptionalYour unique reference id. Auto-generated if omitted; must be unique.
bank_namestringOptionalFree text.
notestringOptionalUp to 1000 chars.

Per-type required fields

In addition to the common block above.

requested_typeRequired extra fieldsForbidden fields
UPI upi_address account_number, ifsc_code
RTGS_IMPS account_number, ifsc_code upi_address
CASH (none) upi_address, account_number, ifsc_code

A payout is always settled on the rail you originally requested — if you ask for UPI, you will receive a UPI settlement; the transfer_type on the webhook will match requested_type.

Success · 201 Created

Returns the full payout row. It includes a reference_id (e.g. "PO-7313D4583375") — a unique identifier we generate on our end for this payout. Use it to reconcile the webhook callback with the row you created. The row also returns is_transferred=false, transfer_type=null, reference_number=null, trx_fees="0" and net_amount="0". Those are filled in once the payout is settled and a webhook is delivered (see §3.2).

Validation errors

400

If you submit a field that does not belong to the chosen requested_type, the error for that field is "Not allowed for requested_type=<...>."

{
    "requested_type": "UPI",
    "first_name": "Aditya",
    "account_holder_name": "Aditya Verma",
    "upi_address": "aditya@okicici",
    "amount": 1500
}
Response · 201 Created
{
    "id": 911,
    "reference_id": "PO-7313D4583375",
    "requested_type": "UPI",
    "first_name": "Aditya",
    "account_holder_name": "Aditya Verma",
    "upi_address": "aditya@okicici",
    "amount": 1500,
    "is_transferred": false,
    "transfer_type": null,
    "reference_number": null,
    "trx_fees": "0",
    "net_amount": "0"
}
Validation error · 400
{
    "upi_address": ["This field is required for requested_type=UPI."],
    "amount": ["Must be greater than 0."]
}

2.2 Payout status#

GET /api/payout-requests/status/ Auth · X-UPS-KEY

Pull the current status of a payout request. Look it up by either your reference_id or the payout_request_id (the id returned at creation). Supply at least one.

Query parameters

ParameterNotes
reference_idThe payout reference_id, e.g. PO-7313D4583375.
payout_request_idThe numeric id returned when the payout was created.

payout_status is one of pending transferred rejected

Errors

400

Bad Request — neither reference_id nor payout_request_id supplied — {"status": "failed", "message": "Provide reference_id or payout_request_id."}

404

Not Found — no payout matches for your account — {"status": "failed", "message": "Payout request not found"}

Request
GET /api/payout-requests/status/?reference_id=PO-7313D4583375
X-UPS-KEY: Api-Key <company key>

GET /api/payout-requests/status/?payout_request_id=911
X-UPS-KEY: Api-Key <company key>
Response · 200 OK
{
    "status": "success",
    "message": "success",
    "data": {
        "id": 911,
        "reference_id": "PO-7313D4583375",
        "amount": 1500.0,
        "trx_fees": "15.00",
        "net_amount": "1515.00",
        "transfer_type": "UPI",
        "reference_number": "123456789012",
        "is_transferred": true,
        "is_rejected": false,
        "note": "Settled",
        "payout_status": "transferred",
        "currency": "INR",
        "original_request": {
            "reference_id": "PO-7313D4583375",
            "requested_type": "UPI",
            "amount": "1500.0",
            "first_name": "Aditya",
            "account_holder_name": "Aditya Verma",
            "upi_address": "aditya@okicici",
            "account_number": null,
            "ifsc_code": null,
            "bank_name": null,
            "reference_number": "123456789012",
            "mobile_number": null,
            "location": null
        },
        "created_at": "2026-04-29T14:39:16.821000Z",
        "updated_at": "2026-04-29T14:43:10.245112Z"
    }
}
3

Webhooks#

The platform calls a partner-supplied URL for each terminal status change. Webhook URLs are configured per type during onboarding — three URLs for inbound transactions (UPI / RTGS_IMPS_NEFT / CASH) and three for payouts.

HTTP details

Method & body

Method: POST
Body: application/json

Timeouts

Connect timeout: 2 s · Read timeout: 5 s

Retries

Success = any 2xx response. Anything else is retried once after 20 s, and then marked as failed.

Signing

Webhooks are not signed today — host the receiving endpoint over HTTPS at a secret URL.

3.1 Transaction webhook#

POST <your URL for the transaction's account_type>

Fires when a transaction reaches a terminal state (approved or rejected). Routed to the URL configured for the transaction's account_type.

trx_status is one of approved rejected pending — pending transactions are not webhooked.

{
    "id": 4711,
    "amount": 500.0,
    "is_verified": true,
    "source": "checkout-web",
    "rejected": false,
    "updated_at": "2026-04-29T14:43:10.245112Z",
    "created_at": "2026-04-29T14:39:16.821000Z",
    "reference_id": "ORD-1029",
    "utr": "123456789012",
    "trx_status": "approved",
    "account_type": "UPI",
    "currency": "INR",
    "trx_fees": "10.00",
    "net_amount": "490.00"
}

3.2 Payout webhook#

POST <your URL for the payout's transfer_type>

Fires when a payout is settled (transferred) or rejected. Routed to the URL configured for the payout's transfer_type.

The payload includes a top-level reference_id (the unique id we returned when you created the payout) plus an original_request block that echoes the values you sent in §2.1, so you can match the callback to the row you created without having to track our id.

payout_status is one of transferred rejected pending — pending payouts are not webhooked.

{
    "id": 911,
    "reference_id": "PO-7313D4583375",
    "amount": 1500.0,
    "trx_fees": "15.00",
    "net_amount": "1515.00",
    "transfer_type": "UPI",
    "reference_number": "BANKREF-998877",
    "is_transferred": true,
    "is_rejected": false,
    "note": "Sent via PhonePe",
    "payout_status": "transferred",
    "currency": "INR",
    "original_request": {
        "requested_type": "UPI",
        "amount": "1500.00",
        "first_name": "Aditya",
        "account_holder_name": "Aditya Verma",
        "upi_address": "aditya@okicici",
        "account_number": null,
        "ifsc_code": null,
        "bank_name": null
    },
    "created_at": "2026-04-29T13:20:01.000000Z",
    "updated_at": "2026-04-29T14:11:12.500000Z"
}
4

Errors#

HTTPBody shapeMeaning
400 {"<field>": ["<message>"]} or {"message": "..."} Validation failure.
401 {"detail": "..."} Missing or invalid auth header.
403 {"detail": "..."} The endpoint does not allow your auth scheme.
404 {"detail": "...not found"} Resource does not exist.
5xx {"message": "Please try again later."} Transient server error — safe to retry idempotently using the same reference_id.

Status values#

trx_status

Transactions · §1.2, §1.3, §3.1

pending Awaiting payment — never webhooked.

approved Terminal · payment received and verified.

rejected Terminal · payment failed or was declined.

payout_status

Payouts · §2.2, §3.2

pending Queued for settlement — never webhooked.

transferred Terminal · money sent on the requested rail.

rejected Terminal · see note for the reason.

UPS Payments — API Reference · Transactions, Payouts & Webhooks.

Replace {{BASE}} with the API base URL given to you during onboarding.