Available in🇮🇳 India
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.capturedlands beforeorder.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
201for ₹2.01 and100for ₹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.
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@razorpayas the VPA with100(₹1) on both the order and the payment to succeed. - Send
failure@razorpaywith 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.
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
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 1 | Successful payment | success@razorpay + amount: 100 | 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. 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. |
| 2 | Customer cancels | failure@razorpay + 302 | 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.failed with payment_cancelled. The order stays open. |
| 3 | Request expires | failure@razorpay + 301 | 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_collect_request_expired. Stop polling and let the customer retry. |
| 4 | Fetch payment and reconcile (all methods) | A payment ID from 1 (success) and one from any row in 3.3 UPI error scenarios | Poll 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
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 5 | Full and partial refund (all methods) | A captured payment from 1 | Refund 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.| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 6 | Bank technical error | failure@razorpay + 104 | code GATEWAY_ERRORsource issuer_bankstep payment_debit_responsereason 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. |
| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 7 | Insufficient funds | failure@razorpay + 201 | code GATEWAY_ERRORsource customerstep payment_debit_requestreason 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. |
| 8 | Wrong UPI PIN | failure@razorpay + 204 | code BAD_REQUEST_ERRORsource customerstep payment_authenticationreason 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. |
| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 9 | Declined by bank or risk check | failure@razorpay + 404 | code GATEWAY_ERRORsource issuer_bankstep payment_debit_responsereason 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. |
| 10 | API validation errors (all methods) | Missing amount, amount: 0, wrong key secret | — | Send each bad request. Confirm HTTP 4xx, no payment created, no webhook. |
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