Available in🇮🇳 India
Use Test Mode to check your card recurring integration before you go live. Test Mode simulates the card network, mandate hub and bank responses, so you can register mandates, run subsequent debits and handle failures without moving real money. This page covers S2S integrations. See UPI Autopay Intent for the UPI equivalent.
Start with the overview for test keys and webhook setup.
Before you startEvery scenario on this page needs an order. Order behaviour has scenarios of its own, all on Orders. The ones that matter for this method: ORD-20 mandate order, ORD-21 mandate order errors, ORD-22 a new order per subsequent debit, ORD-04 signature, ORD-05 idempotent create, ORD-06 fetch. Request errors (ORD-08 to ORD-15) are the same for every method; run them once.
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
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 rely on webhooks
- 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.
Token states
Charge a token only while it isconfirmed.
2. Before You Begin
- Use your test keys (
rzp_test_...). The APIs and requests are the same as in live mode; only the keys change. - Configure a webhook URL in your Test Mode Dashboard to receive test events.
- Test Mode has a mock bank page with Success and Failure buttons. No real money is deducted.
- In Test Mode, the card number decides the scenario. To use a test card:
- Create the authorisation payment and pass the card for your scenario in
card.number. Use any CVV and any future expiry date. - Redirect the customer to the authentication URL returned in the response. A mock bank page is displayed.
- Choose Success to register the mandate, or Failure for a registration failure card.
- Create the authorisation payment and pass the card for your scenario in
- For subsequent debits, register with the same card number first, then charge the token. The subsequent debit reaches its final state about 5 minutes later.
3. Scenarios to Test Your Integration
This section lists the scenarios worth running against your card recurring integration before you go live. They are grouped by what each one proves, so that you can work down the page in order and cover the integration end to end. Must-have. Run these first. They cover registration, the subsequent debit and the outcomes you are almost certain to meet once you are live, including a failed registration and a failed subsequent debit. Other common scenarios. These come up in normal running: Native OTP and bank redirect, eligibility checks, a token rejected after registration, cards that can’t be used for recurring, AFA, token checks and token management. Error scenarios. Failures you bring on deliberately with a test card, so that you can check your error handling without waiting for a real failure. Each row uses one test card. Not available in test mode yet. These are real scenarios your integration has to handle, but they can’t be reproduced in Test Mode today.3.1 Must-have
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 1 | Register a mandate | 4100 2800 0000 1007 (Visa), 5305 6200 0006 0000 (Mastercard) or 6527 6589 0000 1005 (RuPay) + Success | Create a customer (POST /v1/customers) and store the returned customer_id. Create an order (POST /v1/orders) with method: "card", the customer_id and a token object (max_amount, expire_at, frequency). Create the authorisation payment (POST /v1/payments/create/json, recurring: true) with the trigger card in card.number, any CVV and any future expiry date. Redirect to the authentication URL in the response, and choose Success on the mock bank page. Webhooks received: payment.authorized, payment.captured, order.paid, token.confirmed. Status changes: the payment moves to captured and the token to confirmed. Store the token_id; you need it for every subsequent debit. |
| 2 | Registration fails: insufficient funds | 4100 2800 0008 0001 + Failure | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed with insufficient_funds. The mandate is not registered. Let the customer retry the registration, for example with another card. |
| 3 | Subsequent debit succeeds | Same card as #1 | Register a mandate (#1). Create a new order (POST /v1/orders) for the subsequent debit, then charge the token (POST /v1/payments/create/recurring), or charge it from the Dashboard. Wait about 5 minutes (poll with a timeout). Confirm payment.captured and order.paid. |
| 4 | Subsequent debit fails: insufficient funds | 4718 6000 0007 0021 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token, or charge it from the Dashboard. Confirm payment.failed with insufficient_funds. Token stays active. |
| 5 | Mandate cancelled before the subsequent debit | 4718 6091 2000 0016 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm card_mandate_not_active. Confirm you stop scheduling subsequent debits on this token. |
| 6 | Mandate paused before the subsequent debit | 4718 6091 2007 0019 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm card_mandate_paused. Confirm you stop scheduling subsequent debits on this token. |
3.2 Other common scenarios
| # | Scenario | Trigger creds | Steps to follow |
|---|---|---|---|
| 7 | Register with a card that supports Native OTP | 5305 6200 0006 0000 | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. The customer enters the OTP on the Razorpay page. Confirm the mandate registration succeeds and token.confirmed is sent. |
| 8 | Register with a card that doesn’t support Native OTP | 4100 2800 0000 1007 | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. The customer is redirected to the mock bank page; choose Success. Confirm the mandate registration succeeds and token.confirmed is sent. |
| 9 | Check recurring eligibility with the IIN API | GET /v1/iins/:iin (on-demand) | Call the IIN API with the card’s IIN before you create the registration payment. The IIN API is an on-demand feature; ask Support to enable it on your account. Confirm you block registration when recurring.available is false. |
| 10 | Registration payment succeeds, token rejected later | 4100 2800 0005 0012 + Success | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Success on the mock bank page. Confirm payment.captured, then token.rejected. The token is rejected at the mandate hub because the card BIN isn’t supported. Confirm you don’t schedule subsequent debits. Treat the mandate as live only after token.confirmed. |
| 11 | Card not eligible for recurring | 4100 2800 0006 0011 + Failure | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed with card_mandate_card_not_supported. Ask the customer to use a different card. |
| 12 | Card BIN not supported for recurring | 6527 6500 0007 0022 + Failure | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed with card_mandate_bin_not_supported. Ask the customer to use a different card. |
| 13 | Customer doesn’t approve AFA | 4718 6091 2009 0017 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm customer_action_required and your customer prompt. |
| 14 | Subsequent debit on a token that isn’t confirmed | 4718 6091 2002 0014 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm the create payment request is rejected with token_not_eligible and no payment is created. Read the error from the API response; no payment webhook is sent. |
| 15 | Subsequent debit on an expired token | 4718 6091 2008 0018 | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm the payment is created and then fails with token_expired. |
| 16 | Fetch and delete tokens | A token from scenario 1 | Fetch the token created by the registration payment: GET /v1/payments/:id (the response contains token_id). Fetch all tokens for the customer: GET /v1/customers/:id/tokens. Delete the token: DELETE /v1/customers/:customer_id/tokens/:token_id. Confirm the status changes to cancelled and token.cancelled is sent. The token is not removed from Razorpay. |
3.3 Error scenarios
Registration These happen while the customer is registering the mandate. The registration payment fails, so the mandate is not registered and you can’t create subsequent debits. The customer has to start the registration again.| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 17 | Customer cancels the payment | 4100 2800 0007 0002 + Failure | code BAD_REQUEST_ERRORsource customerstep payment_authenticationreason payment_cancelled | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| 18 | Payment times out | 4100 2800 0009 0000 + Failure | code BAD_REQUEST_ERRORsource customerstep payment_authenticationreason payment_timed_out | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| 19 | Incorrect OTP or verification details | 4100 2800 0000 0009 + Failure | code GATEWAY_ERRORsource customerstep payment_authenticationreason authentication_failed | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| 20 | Card not enabled for online payments | 4100 2800 0004 0013 + Failure | code GATEWAY_ERRORsource customerstep card_enrollment_checkreason card_not_enrolled | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| 21 | Declined by the issuing bank | 4100 2800 0005 0004 + Failure | code BAD_REQUEST_ERRORsource issuer_bankstep payment_authorizationreason card_declined | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| 22 | Card disabled for online payments | 4100 2800 0003 0006 + Failure | code BAD_REQUEST_ERRORsource issuer_bankstep payment_authorizationreason card_disabled_for_online_payments | Create a customer and an order as in #1. Create the authorisation payment with the trigger card, any CVV and any future expiry date. Redirect to the authentication URL, and choose Failure on the mock bank page. Confirm payment.failed and the error object. Let the customer retry the registration. |
| # | Scenario | Trigger creds | Error object | Steps to follow |
|---|---|---|---|---|
| 23 | Pre-debit notification fails | 4718 6091 2001 0015 | code BAD_REQUEST_ERRORsource issuer_bankstep pre_debit_notification_verifyreason pre_debit_notification_failed | Register a mandate with the trigger card, choosing Success (#1). Create a new order for the subsequent debit, then charge the token. Confirm payment.failed with the error object about 5 minutes after you create the payment. |
amount, currency, receipt and so on) are on Orders → Simulate failures.
3.4 Not available in test mode yet
These scenarios can’t be reproduced in Test Mode today, but your integration still has to handle them. Each row gives the behaviour your code has to implement.4. Common Integration Gaps to Avoid
These are the mistakes that most often cause failed payments, missed subsequent debits or double charges after go-live. “Test with” gives the scenario numbers in section 3 that prove you’ve handled it.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