Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.cashfree.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

UPI One-Time Mandate (OTM) is a secure, RBI-compliant payment workflow that allows you to block a specific amount from a customer’s UPI-linked bank account upfront and debit it only after the order or service has been fulfilled. This two-step block-then-capture model gives you confidence in fund availability before debiting, and gives customers a transparent authorisation trail in their UPI app.

Key benefits

UPI OTM offers the following benefits:
  • Guaranteed fund availability: You block funds at order time and capture only after fulfilment.
  • Customer trust and transparency: Your customers approve the mandate in their UPI app and see the block in real time.
  • Flexible capture: You can capture any amount up to the authorised order value.
  • Auto-release on void: If the order is cancelled, funds are unblocked through a simple void request to the Preauthorisation API.
  • UPI channel support: You can use UPI Collect, UPI Intent, or UPI QR based on your checkout experience.

Use cases

Use UPI OTM when you need to confirm payment availability before finalising an order. Common scenarios include:
  • IPO applications: Reserve funds for ASBA requests and debit only if the allotment succeeds.
  • Insurance approvals: Block the premium amount until underwriting is completed.
  • Variable utility or charging services: Hold funds when the final amount is not known at the time of booking.
  • Healthcare and hospital services: Reserve a provisional amount while insurance coverage or treatment costs are confirmed.
  • Rental deposits: Hold a refundable deposit and charge only for actual damages.
  • Travel and hospitality reservations: Reserve funds for bookings while preserving flexibility for cancellations.
  • Limited-stock product launches: Reserve funds for high-demand orders and collect payment only once the order is confirmed.
Set approve_by to a short window to reduce abandoned mandates, and choose start_time and end_time based on your fulfilment SLA.

UPI OTM lifecycle

The UPI OTM lifecycle consists of four stages. Each stage maps to a Cashfree API call.
  1. Create an order and payment session: Create an order with the Create Order API, then initiate a UPI mandate payment session with the Order Pay API using authorize_only: true to block funds without immediately debiting the customer’s account.
  2. Get customer approval to block funds: Your customer approves the mandate in their UPI app. You receive a SUCCESS webhook, and the funds are blocked without immediate debit.
  3. Capture the mandate on fulfilment: After you fulfil the order, call the Preauthorisation API with action: CAPTURE to debit the blocked amount.
  4. Void the mandate or process a refund: If the order is cancelled before capture, call the Preauthorisation API with action: VOID to release the block. If the order is already captured, create a refund with the Create Refund API instead.

Supported UPI channels

UPI OTM works across the following channels:
channel valueChannel nameWhen to use
collectUPI CollectCashfree sends a collect request to the customer’s UPI app.
linkUPI IntentA deep link opens the customer’s UPI app directly on mobile.
qrcodeUPI QRA QR code is generated for the customer to scan and approve the mandate.

Integrate the UPI OTM flow

Use the following steps to create orders, start a UPI mandate session so customers can approve a block, capture or void the authorisation, and issue refunds after capture.
1

Create an order and payment session

Create an order with Cashfree using the Create Order API and your order and customer details.Use the following cURL example as a template when you call the API from your application.
Request sample
curl --request POST \
    --url https://api.cashfree.com/pg/orders \
    --header 'x-client-id: <CLIENT_ID>' \
    --header 'x-client-secret: <CLIENT_SECRET>' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --header 'x-api-version: 2023-08-01' \
    --data '{
    "order_amount": 100.00,
    "order_currency": "INR",
    "order_id": "devstudio_4809486",
    "customer_details": {
        "customer_id": "devstudio_user",
        "customer_phone": "8474090589"
    },
    "order_meta": {
        "return_url": "https://www.cashfree.com/devstudio/preview/pg/web/checkout?order_id={order_id}"
    }
}'
2

Create UPI mandate session to block funds

Create the OTM transaction with Cashfree using the Order Pay API.The sample below uses UPI Collect; you can adapt the payload for your channel.
UPI Collect
curl --request POST \
    --url https://api.cashfree.com/pg/orders/sessions \
    --header 'x-client-id: <CLIENT_ID>' \
    --header 'x-client-secret: <CLIENT_SECRET>' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --header 'x-api-version: 2023-08-01' \
    --data '{
    "payment_method": {
        "upi": {
            "channel": "collect",
            "upi_id": "testsuccess@gocash",
            "authorize_only": true,
            "authorization": {
                "approve_by": "2024-07-02T10:20:12+05:30",
                "start_time": "2024-09-21T12:34:34Z",
                "end_time": "2024-10-22T12:34:34Z"
            }
        }
    },
    "payment_session_id": "sessionid"
}'
For UPI Intent or UPI QR, use the following channel values:
  • link for UPI Intent
  • qrcode for UPI QR
Cashfree calls the acquiring bank to create an OTM transaction. If the customer approves the mandate, you receive a SUCCESS response and a webhook notification. The amount is blocked in the customer’s account, but no amount is debited at this stage.
The mandate blocks funds but does not debit them immediately. Capture the amount only when you are ready to complete the transaction.
3

Capture the mandate

To capture the mandate, call the Preauthorisation API with the CAPTURE action.
The captured amount must be less than or equal to the order amount.
Use the following cURL example when you send a capture action for the order.
Capture mandate
curl --request POST \
     --url https://api.cashfree.com/pg/orders/<ORDER_ID>/authorization \
     --header 'Accept: application/json' \
     --header 'x-client-id: <CLIENT_ID>' \
     --header 'x-client-secret: <CLIENT_SECRET>' \
     --header 'Content-Type: application/json' \
     --header 'x-api-version: 2023-08-01' \
     --data '{
  "action": "CAPTURE",
  "amount": 100
}'
Cashfree calls the acquiring bank to capture the mandate. If the capture succeeds, the payment amount is settled to you according to the settlement cycle.In most cases, capture succeeds immediately. For a small percentage of requests, you receive a failure response and the final outcome is confirmed later. For details on handling these cases, see Capture error codes and handling.
4

Void the mandate or process a refund

Choose one path: void releases a block only before capture; refund applies only after capture. You do not run both for the same order.To void the mandate before capture, call the Preauthorisation API with the VOID action.Use the following cURL example when you void an authorisation.
Void mandate
curl --request POST \
     --url https://api.cashfree.com/pg/orders/<ORDER_ID>/authorization \
     --header 'Accept: application/json' \
     --header 'x-client-id: <CLIENT_ID>' \
     --header 'x-client-secret: <CLIENT_SECRET>' \
     --header 'Content-Type: application/json' \
     --header 'x-api-version: 2023-08-01' \
     --data '{
  "action": "VOID"
}'
Cashfree calls the acquiring bank to void the mandate. If the void succeeds, the blocked amount is released from the customer’s account.
If the bank returns a failure response, Cashfree automatically retries the void up to three times. If the void does not succeed, the blocked funds are released automatically at mandate expiry (end_time).
To refund after capture, use the Create Refund API instead of void. A refund can be initiated only after the transaction is captured. Use the following steps to process a refund:
  1. Call the Create Refund API to initiate the refund.
  2. Cashfree submits the refund to the acquiring bank for processing.
  3. If processing succeeds, the amount is refunded to the customer.
  4. If the refund fails, Cashfree retries every six hours for up to five attempts.
Use the following cURL example when you complete step 1 with the Create Refund API.
Create refund
curl --request POST \
    --url https://api.cashfree.com/pg/orders/<ORDER_ID>/refunds \
    --header 'x-client-id: <CLIENT_ID>' \
    --header 'x-client-secret: <CLIENT_SECRET>' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --header 'x-api-version: 2023-08-01' \
    --data '{
  "refund_amount": 100,
  "refund_id": "refund_001"
}'
If the refund remains unsuccessful after all retry attempts, Cashfree coordinates directly with the bank to process the refund offline.

Capture error codes and handling

For a small percentage of captures from the Preauthorisation API that do not return an immediate success, Cashfree returns one of the following error codes. Each code has a defined resolution path.
Error codeMeaningWhat to expect
59Processing delay at bankCashfree escalates to NPCI. Delayed success can be delivered on T+5 business days.
K1Bank timeout or holdCashfree escalates to NPCI. Delayed success can be delivered on T+5 business days.
VHBank hold or verification holdCashfree escalates to NPCI. Delayed success can be delivered on T+5 business days.
VOVoid override (not settable)The transaction is not settled. No further action is available through Cashfree for this capture attempt.
Error codes 59, K1, and VH are recoverable. Cashfree escalates these to NPCI and the settlement may arrive within T+5 business days. Error code VO is non-recoverable and has a very low occurrence rate.

Integration checklist

Use the following checklist to validate a complete UPI OTM integration:
  • Obtain x-client-id and x-client-secret from the Merchant Dashboard.
  • Create an order using the Create Order API and store the payment_session_id.
  • Initiate the UPI OTM session with the Order Pay API using authorize_only: true and the required channel.
  • Call the Preauthorisation API with action: CAPTURE after fulfilment.
  • Call the Preauthorisation API with action: VOID for cancellations before capture.
  • Create a refund using the Create Refund API only for orders already captured.
  • Handle error codes 59, K1, and VH by waiting up to T+5 business days for delayed settlement confirmation from NPCI.