Skip to main content
Available in🇮🇳 India
Collect is deprecated from 28 February 2026. Exemptions: specific MCCs, iOS and mobile web, UPI Mandates, eRupi vouchers and PACB businesses. Everyone else should build and test Intent (mobile) and QR (desktop).
Send collect requests, simulate failures and reconcile against the webhooks in test mode, then check VPA validation and the approval window on live traffic before you go live. This page covers one-time UPI Collect payments on S2S: you send a payment request to the customer’s UPI ID and they approve it inside their UPI app. UPI flows: Intent · QR · Collect Start with the overview for test keys and webhook setup.

1. Test Mode Coverage

How live mode and test mode differ

What you can test

Endpoint coverage in test mode

Webhooks: what fires, and what it lets you decide

Every webhook this flow fires in live mode is listed below, along with whether it also fires in test mode. Test mode webhooks have the same shape as live mode ones and are delivered to the URL set in your test mode Dashboard. Which webhooks each scenario fires Before you trust any of them
  • Verify the signature on every event. Replay one event to your endpoint and send one with a changed body. The replay must be ignored and the tampered event rejected. An endpoint that skips this is an open write to your order state.
  • Expect duplicates. The same event can arrive more than once. Key your handler on the event ID and make it idempotent.
  • Order is not guaranteed across events. Do not assume payment.captured lands before order.paid; handle whichever arrives first.
  • Webhook first, callback second. The browser callback can be lost, blocked or forged. Fulfil on the webhook.

2. Before you begin

  • Generate your test mode API keys from the Dashboard. Keys that start with rzp_test_ send all requests to test mode. You do not need to enable any separate flag.
  • Use the same APIs and request formats you use in live mode. Only the API keys change.
  • Pass every amount in paise, as you do in live mode. For example, send 201 for ₹2.01 and 100 for ₹1.
  • Configure a webhook URL in your test mode Dashboard to receive test events. Test mode webhooks are separate from live mode ones and do not carry over.
In test mode the amount you send decides the outcome, because there is no real bank on the other end. Send 100 (₹1) and the payment succeeds. Send one of the reserved amounts and the payment fails with the error mapped to that amount. For example, create the order for 201 (₹2.01) and the payment always fails with an insufficient balance error, so you can check that your code handles that case without waiting for a real account to run out of money.
  • Send success@razorpay as the VPA with 100 (₹1) on both the order and the payment to succeed.
  • Send failure@razorpay with a reserved amount from 3.3 UPI error scenarios to fail with the error mapped to that amount.
  • No collect request reaches a UPI app, so there is nothing to approve.
  • Any amount that is not in the reserved list succeeds.
Amounts are in paise and follow one pattern: 1xx bank and network, 2xx account and limits, 3xx customer action, 4xx validation and risk.

3. Scenarios to Test Your Integration

This section lists every scenario we think is worth running against your UPI Collect integration before you go live. They are grouped by what each one proves, rather than by how urgent they are, so that you can work down the page in order and know that you have covered the integration end to end. Must-have. We highly recommend running these scenarios first. They cover the successful path and the handful of outcomes you are almost certain to meet once you are live, so getting through them is the shortest route to an integration you can trust. Other common scenarios. These come up in normal day-to-day running and are shared across one-time UPI and UPI Autopay, so the same handling has to work on both. They are not errors as such, but your integration still needs to recognise them and respond correctly, so we recommend covering them before launch. Error scenarios. These are failures you can bring on deliberately, using a reserved trigger, so that you can check your error handling without waiting for a real failure to happen. Not available in test mode yet. These scenarios are real and your integration still has to handle them, but they cannot be reproduced in test mode today. We recommend reading through them and checking your handling on live traffic or in a controlled live test before you ship.

3.1 Must-build UPI scenarios

#ScenarioTrigger credsSteps to follow
1Successful paymentsuccess@razorpay + amount: 100Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Verify the signature on your server. Confirm payment.captured. Webhooks received: payment.authorized, payment.captured, order.paid. Status changes: the payment moves to captured and the order to paid.
2Customer cancelsfailure@razorpay + 302Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm payment.failed with payment_cancelled. The order stays open.
3Request expiresfailure@razorpay + 301Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm payment_collect_request_expired. Stop polling and let the customer retry.
4Fetch payment and reconcile (all methods)A payment ID from 1 (success) and one from any row in 3.3 UPI error scenariosPoll GET /v1/payments/:id while the customer is in the UPI app. Confirm the status matches the webhook. Repeat scenario 1 with failure@razorpay and each reserved amount to cover the error scenarios in 3.3, and show the expiry timer so the customer knows how long they have to approve in their UPI app.

3.2 Common scenarios in UPI

#ScenarioTrigger credsSteps to follow
5Full and partial refund (all methods)A captured payment from 1Refund in full and in part. Confirm refund.processed.

3.3 UPI error scenarios

Bank and network (1xx) The payment reached the rails and something outside the customer’s control went wrong. These are temporary, so offer the customer the same method again.
#ScenarioTrigger credsError objectSteps to follow
6Bank technical errorfailure@razorpay + 104code GATEWAY_ERROR
source issuer_bank
step payment_debit_response
reason bank_technical_error
Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm bank_technical_error and a retry option.
Account and limits (2xx) The customer’s account, their PIN or their bank’s limits stopped the debit. A few are recoverable on the same account, a wrong PIN above all; most are not. Read the reason before you offer a retry.
#ScenarioTrigger credsError objectSteps to follow
7Insufficient fundsfailure@razorpay + 201code GATEWAY_ERROR
source customer
step payment_debit_request
reason insufficient_funds
Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm insufficient_funds and a “use another account” message.
8Wrong UPI PINfailure@razorpay + 204code BAD_REQUEST_ERROR
source customer
step payment_authentication
reason incorrect_pin
Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm incorrect_pin and a retry option.
Validation and risk (4xx) The request or the customer failed a check before or during the debit. Read the reason before you decide whether a retry is worth anything.
#ScenarioTrigger credsError objectSteps to follow
9Declined by bank or risk checkfailure@razorpay + 404code GATEWAY_ERROR
source issuer_bank
step payment_debit_response
reason payment_risk_check_failed
Create an order with the trigger amount. Create the payment: POST /v1/payments/create/upi with upi.flow: "collect" and upi.vpa. Show a “complete the payment in your UPI app” state with a timer. Confirm payment_risk_check_failed.
10API validation errors (all methods)Missing amount, amount: 0, wrong key secret—Send each bad request. Confirm HTTP 4xx, no payment created, no webhook.
The full list of UPI error reasons, including the ones no trigger reproduces in test mode, is on the Error index.

3.4 Not available in test mode yet

4. Common Integration Gaps to Avoid

These are the mistakes that most often cause failed payments, missed debits or double charges after go-live. “Test with” points to the scenario that proves you’ve handled it. Before you send — validate the VPA (Collect only) Webhook and token updates Saved VPA (Collect only) Error handling and messaging to the payer Fetch API when webhooks are late Capture & refunds

5. Best Integration Practices

These apply to every Razorpay integration. “On this method” says what each one means here; “Test it” links to where it is tested once for every method. All best practices: Overview · Webhooks and Fetch APIs · Payment states and late authorisation · Error handling · Downtime handling · Security
Last modified on November 12, 2026