Available in🇮🇳 India
Register mandates, run auto-debits, simulate failures and manage tokens in Test Mode, then work through the pre-launch checklist before you go live.
Use Test Mode to check your UPI Autopay integration before you go live. Test Mode simulates the responses from NPCI and the customer’s bank, so you can register mandates, run auto-debits and handle failures without moving real money or using a UPI app. This page describes how to test the request and response payload across each API call, and what error scenarios to expect.
UPI Autopay 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 UPI Autopay 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
Watch out. Note the
order. prefix. The pre-debit notification events are named order.notification.delivered and order.notification.failed, not notification.delivered and notification.failed. We recommend subscribing to them and verifying them against live traffic, since neither fires in Test Mode yet.Handy tip. A webhook can be delivered more than once. Use the event ID to make sure you process each event only once. This applies in live mode as well.
Token states
Charge a token only while it isconfirmed.
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.
- Send
100(₹1) on both the order and the payment to succeed. - Send a reserved amount from 3.3 Autopay error scenarios on both calls to fail. For debits, keep it below the mandate’s
max_amount. - No collect request reaches a UPI app, so there is nothing to approve.
- Any amount that is not in the reserved list succeeds.
notification object and who owns the retries are defined in the published integration doc: Subsequent Payments. This page does not redefine them.
3. Scenarios to Test Your Integration
This section lists every scenario we think is worth running against your UPI Autopay 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. Most rows use a single trigger, which keeps the error you get back unambiguous. 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 Autopay scenarios
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 1 | Register a mandate | amount: 100 | Create a customer (POST /v1/customers) and store the returned customer_id. Create an order (POST /v1/orders) with method: "upi", the customer_id and a token object, using the trigger amount. Create the authorisation payment (POST /v1/payments/create/upi, recurring: 1) with the same amount. upi.flow: "collect" and upi.vpa (any well-formed VPA). Show an “approve the mandate in your UPI app” state. Confirm token.confirmed. Store the token ID from payment.authorized. On the order and the payment. |
| 2 | Subsequent debit succeeds | amount: 100 | Register a mandate (#1). Create a debit order without the notification object, which is what places the payment on the coupled flow, and a recurring payment (POST /v1/payments/create/recurring) with the trigger amount. Confirm payment.captured and order.paid. Token stays confirmed. |
| 3 | Debit fails: insufficient funds | amount: 201 | Register a mandate (#1). Create a debit order and a recurring payment (POST /v1/payments/create/recurring) with the trigger amount. Confirm payment.failed with insufficient_funds. Token stays active. |
3.2 Common scenarios in UPI
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 4 | Debit with your own pre-debit notification | amount: 100 | Register a mandate (#1). Create the debit order (POST /v1/orders) with the notification object, setting notification.token_id and notification.payment_after. Create the recurring payment (POST /v1/payments/create/recurring) with the same amount, passing order_id, customer_id, token and recurring: true. Confirm payment.captured. |
| 5 | Fetch tokens | A sample token ID | Take a sample token ID from a mandate you registered earlier. GET /v1/customers/:customer_id/tokens/:token_id and GET /v1/customers/:customer_id/tokens. Confirm status, max_amount, expire_at, frequency. |
| 6 | Fetch a payment and reconcile (also on one-time UPI) | A payment ID from the registration in scenario 1 and one from any row in 3.3 | Poll GET /v1/payments/:payment_id for each payment. Confirm the status your reconciler reads matches the status the webhook carried. Confirm a payment still in created is never treated as final. |
| 7 | Full and partial refund (also on one-time UPI) | A captured debit payment from scenario 2 | Refund in full with POST /v1/payments/:payment_id/refund, and refund another captured debit in part. Webhooks received: refund.processed. Confirm the mandate is untouched. A refund does not cancel the token, and the next debit still runs. |
| 8 | API validation errors (also on one-time UPI) | Missing amount, amount: 0, wrong key secret | Send each bad request to the order and the payment endpoints. Confirm HTTP 4xx, no payment created and no webhook. Read the API error response rather than waiting for an event, because none fires. |
3.3 Autopay error scenarios
Registration These happen while the customer is setting the mandate up, so the token never reachesconfirmed and no debit is possible. In each case the customer has to start the registration again.
| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 9 | Customer cancels the mandate request — mandate_cancelled_by_user, source: internal | amount: 302 | code BAD_REQUEST_ERRORsource internalstep payment_responsereason mandate_cancelled_by_user | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm payment.failed and token.rejected. Let the customer restart. |
| 10 | Customer declines the mandate request — mandate_cancelled_by_user, source: customer | amount: 304 | code GATEWAY_ERRORsource customerstep payment_authenticationreason mandate_cancelled_by_user | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm payment.failed and token.rejected. Let the customer restart. |
| 11 | Customer never approves it and the request expires — mandate_collect_request_expired | amount: 301 | code GATEWAY_ERRORsource customerstep payment_authenticationreason mandate_collect_request_expired | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm payment.failed and token.rejected. Let the customer restart. |
| 12 | Registration fails: insufficient funds | amount: 201 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason insufficient_funds | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm insufficient_funds. |
| 13 | Account not allowed for Autopay | amount: 203 | code GATEWAY_ERRORsource remitter_bankstep payment_authenticationreason account_state_forbidden | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm remitter_account_dormant (source: customer, step: payment_debit_request). |
| 14 | Invalid UPI ID | amount: 401 | code GATEWAY_ERRORsource customerstep payment_debit_requestreason invalid_vpa | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Show an “approve the mandate in your UPI app” state. Confirm invalid_vpa and ask the customer to re-enter their UPI ID. |
| 15 | Duplicate registration request — duplicate_request | amount: 406 | code BAD_REQUEST_ERRORsource internalstep payment_requestreason duplicate_request | Register as above with the trigger amount, sending it on both the order and the authorisation payment. Confirm 400 Bad Request with duplicate_request (source: internal, step: payment_request) and the description “The request is duplicate”. Do not retry the same request. If the earlier payment succeeded no action is needed, otherwise start a fresh registration. |
| 16 | Bank technical error — “Your bank is temporarily unavailable. Please try again later or use a different account.” | amount: 102 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason bank_technical_error | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 17 | Timeout at remitter bank — “Your bank took too long to respond. Please try again.” | amount: 104 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason timeout_at_remitter_bank | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 18 | Bank technical error — “UPI Autopay setup couldn’t be completed due to a temporary issue. Any debited amount will be refunded in 4-5 business days.” | amount: 107 | code GATEWAY_ERRORsource remitter_bankstep payment_authenticationreason bank_technical_error | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 19 | Customer invalid mobile number — “Your mobile number has been changed or removed from this account. Please update your details or use a different account.” | amount: 202 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_responsereason customer_invalid_mobile_number | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 20 | Incorrect pin entered — “Payment authorisation failed due to incorrect MPIN. Please retry with the correct MPIN.” | amount: 204 | code GATEWAY_ERRORsource customerstep payment_initiationreason incorrect_pin_entered | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 21 | Customer mpin not set — “UPI PIN is not set for this account. Please set up your UPI PIN and try again.” | amount: 205 | code GATEWAY_ERRORsource customerstep payment_debit_responsereason customer_mpin_not_set | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 22 | Incorrect pin entered — “You’ve exceeded the number of PIN attempts. Please wait and try again later, or contact your bank if you’ve forgotten your PIN.” | amount: 206 | code GATEWAY_ERRORsource customerstep payment_responsereason incorrect_pin_entered | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 23 | Transaction amount limit exceeded — “This amount is above your transaction limit. Please try a lower amount or contact your bank for assistance.” | amount: 208 | code GATEWAY_ERRORsource remitter_bankstep payment_initiationreason transaction_amount_limit_exceeded | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 24 | Transaction amount limit exceeded — “This amount is above your transaction limit. Please try a lower amount or contact your bank for assistance.” | amount: 209 | code GATEWAY_ERRORsource remitter_bankstep payment_authenticationreason transaction_amount_limit_exceeded | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 25 | Transaction frequency limit exceeded — “You’ve exceeded the number of allowed transactions on this account. Please try again later or contact your bank.” | amount: 210 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason transaction_frequency_limit_exceeded | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 26 | Account state blocked — “Your account is blocked or frozen. Please contact your bank to resolve this.” | amount: 212 | code GATEWAY_ERRORsource remitter_bankstep payment_status_requestreason account_state_blocked | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 27 | Beneficiary account not found — “Payment authorisation failed due to a technical issue. Please try again or contact your bank if this continues.” | amount: 213 | code BAD_REQUEST_ERRORsource businessstep payment_responsereason beneficiary_account_not_found | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 28 | Risk declined by remitter bank — “Autopay setup was blocked for security reasons. Please contact your bank or use a different account.” | amount: 404 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason risk_declined_by_remitter_bank | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 29 | Risk declined by remitter bank — “Autopay setup was declined for security reasons. Please contact your bank for assistance.” | amount: 405 | code GATEWAY_ERRORsource remitter_bankstep payment_initiationreason risk_declined_by_remitter_bank | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
| 30 | Customer PSP fingerprint mismatch — “Payment was declined for security reasons. Please contact your bank for more details.” | amount: 407 | code GATEWAY_ERRORsource customerstep payment_responsereason customer_psp_fingerprint_mismatch | Create a customer, an order and the authorisation payment as in #1, using the trigger amount. Confirm the error object above, and that the token ends at rejected. |
notification object on the order, raise the notification yourself and create the payment separately once the window has passed, and no retries are run on your behalf. For the full description of both, see Subsequent Payments.
These happen on a mandate that is already live. The token stays usable, so the right response is to handle the failed charge rather than to ask the customer to register again.
| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 31 | Debit above max_amount | amount above the token’s max_amount | — | Create a debit order and a recurring payment (POST /v1/payments/create/recurring) for an amount higher than the token’s max_amount. Confirm you get 400 Bad Request with transaction_limit_exceeded (source: remitter_bank), and that no payment object is created. |
| 32 | Debit fails: bank error — remitter_bank_error | amount: 101 | code GATEWAY_ERRORsource remitter_bankstep payment_responsereason remitter_bank_error | Register a mandate (#1). Create a debit order and a recurring payment with the trigger amount. Confirm the failure and that your retry logic treats it as temporary. |
| 33 | Debit fails: unmapped gateway error — gateway_technical_error | amount: 103 | code GATEWAY_ERRORsource gatewaystep payment_responsereason gateway_technical_error | Register a mandate (#1). Create a debit order and a recurring payment with the trigger amount. Confirm gateway_technical_error (source: gateway, step: payment_response). This is the simulator’s catch-all for an error it has no mapping for, so treat it as a temporary failure and retry. |
| 34 | Remitter bank unavailable — “Your bank is temporarily unavailable. Please try again in a few moments.” | amount: 102 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_requestreason remitter_bank_unavailable | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 35 | Timeout at remitter bank — “Your bank took too long to respond. Please try again.” | amount: 104 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_responsereason timeout_at_remitter_bank | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 36 | Remitter bank unavailable — “Your bank is temporarily unavailable. Please try again in a few moments.” | amount: 107 | code GATEWAY_ERRORsource remitter_bankstep payment_requestreason remitter_bank_unavailable | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 37 | Customer mobile changed — “Your registered mobile number has been updated. Please update your UPI profile or contact your bank.” | amount: 202 | code GATEWAY_ERRORsource remitter_bankstep payment_requestreason customer_mobile_changed | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 38 | Customer mpin not set — “UPI PIN is not set for this account. Please set up your UPI PIN and try again.” | amount: 205 | code GATEWAY_ERRORsource customerstep payment_authenticationreason customer_mpin_not_set | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 39 | Incorrect pin entered — “You’ve exceeded the number of PIN attempts. Please wait and try again later, or contact your bank if you’ve forgotten your PIN.” | amount: 206 | code GATEWAY_ERRORsource customerstep payment_authenticationreason incorrect_pin_entered | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 40 | Transaction limit exceeded — “Payment amount exceeds your bank’s limit. Please try with a lower amount or contact your bank to increase the limit.” | amount: 208 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_responsereason transaction_limit_exceeded | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 41 | Spending limit exceeded — “You’ve exceeded your total UPI spending limit. Please try again later or contact your bank to increase the limit.” | amount: 209 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_responsereason spending_limit_exceeded | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 42 | Frequency limit exceeded — “You’ve exceeded the number of allowed transactions. Please try again later or contact your bank.” | amount: 210 | code GATEWAY_ERRORsource remitter_bankstep payment_initiationreason frequency_limit_exceeded | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 43 | Account blocked — “Your account is blocked or frozen. Please contact your bank to resolve this.” | amount: 212 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_requestreason account_blocked | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 44 | Risk declined — “Payment was declined for security reasons. Please contact your bank for assistance.” | amount: 404 | code BAD_REQUEST_ERRORsource businessstep payment_debit_responsereason risk_declined | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
| 45 | Risk declined — “Payment was declined for security reasons. Please contact your bank for assistance.” | amount: 405 | code GATEWAY_ERRORsource remitter_bankstep payment_debit_responsereason risk_declined | Register a mandate first. Create a debit order and a recurring payment with the trigger amount. Confirm the error object above, and that the token stays confirmed so the mandate can be charged again. |
notification object on the debit order you are on the decoupled flow, and four things change. Run the cases above first, then these.
If you integrate against coupled behaviour and later move to decoupled without building the retry loop, every failed debit is silently lost. That is the single most expensive mistake on this flow.
The full list of UPI Autopay error reasons, including the ones no trigger reproduces in test mode, is on the Error index.
3.4 Not available in test mode yet
Not being able to trigger a scenario is not a reason to leave it out of your test suite. Each row below gives the behaviour your code has to implement and the assertion worth writing now, so that the test is already in place when the trigger arrives and so that you can run it against live traffic in the meantime.4. Common Integration Gaps to Avoid
These are the mistakes that most often cause failed payments, missed debits or double charges after go-live. Webhook and token updates
Error handling and messaging to the payer
Fetch API when webhooks are late
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