> ## Documentation Index
> Fetch the complete documentation index at: https://razorpay.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cards: How to Test Your Integration

> Test one-time card payments on S2S JSON and S2S Redirect in Test Mode, including authentication, saved cards, tokens and failure scenarios.

Available in
🇮🇳 India

This page covers one-time card payments on S2S JSON (`POST /v1/payments/create/json`) and S2S Redirect (`POST /v1/payments/create/redirect`). Standard Checkout and Custom Checkout are out of scope for this page.

Start with the [overview](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s.md) for test keys and webhook setup.

> [!NOTE]
>
> **Before you start**
>
> Every scenario on this page needs an order. Order behaviour has scenarios of its own, all on [Orders](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md). The ones that matter for this method: ORD-01 create, ORD-02 lifecycle, ORD-03 retry after a failure, ORD-04 signature, ORD-05 idempotent create, ORD-06 fetch, ORD-07 already paid, ORD-16 partial payments. Request errors (ORD-08 to ORD-15) are the same for every method; run them once.

## 1. Test Mode Coverage

| Behaviour | Live mode | Test mode |
| - | - | - |
| Authentication | Issuer ACS page (3DS) or Native OTP | Mock bank page with Success and Failure buttons. Any OTP of 4–10 digits succeeds; fewer than 4 digits fails. |
| Card numbers | Real cards | Test cards only. In live mode they fail with "card issuer is invalid". |
| Networks and international | As enabled on your live account | As enabled on your test account. A disabled network returns `card_network_not_enabled`. |
| Webhook delivery | Razorpay sends the webhook once the gateway has authorised the payment. That round trip is real, so delivery can take minutes and your reconciler has to allow for it. | The gateway is simulated, so the webhook is sent as soon as the create-payment request succeeds, almost instantly. Do not use test mode to size your reconciliation windows or to judge how long to wait before polling. |
| On-demand features (S2S JSON V2, IIN API, Token HQ) | Enabled per account | Enabled separately for test mode |

| Area | Available on test mode | Note |
| - | - | - |
| Payments | Available | Success, declines, cancel and timeout, fetch |
| Authentication | Available | 3DS redirect, Native OTP, authentication failures |
| Saved cards and tokens | Available | Save, pay with a token, network tokens, Token HQ APIs, one-time on a recurring token |
| BIN / IIN lookup | Available | `GET /v1/iins/:iin` |
| Refunds | Available | Full and partial |
| Manual and partial capture | Coming soon · TBD | — |
| Apple Pay, Card Sync, passkeys, CVV-less, fee bearer, debit card TPV, bulk BIN | Coming soon · TBD | — |

## 2. Test Kit

* Use any future expiry date and any 3-digit CVV (4 digits for Amex).
* On the mock bank page, enter any OTP of 4–10 digits, or choose Success, to approve.
* For a specific error, pay with a card from [Simulate Failures](#8-simulate-failures) and choose Failure. Any other card + Failure returns `gateway_technical_error`.

**Success cards**

| Network | Sub type | Credit | Debit | Prepaid |
| - | - | - | - | - |
| Visa | Consumer | ⚑ New — number TBD | `4100 2800 0000 1007` | ⚑ New — number TBD |
| Visa | Business | ⚑ New — number TBD | ⚑ New — number TBD | n/a |
| Mastercard | Consumer | ⚑ New — number TBD | ⚑ New — number TBD | `5180 2872 0009 1001` |
| Mastercard | Business | `5555 5100 0008 1006` | ⚑ New — number TBD | n/a |
| RuPay | Consumer | `6527 6589 0000 1005` | ⚑ New — number TBD | ⚑ New — number TBD |
| RuPay | Business | ⚑ New — number TBD | ⚑ New — number TBD | n/a |
| American Express | Consumer | `3402 560004 01007` | n/a | n/a |
| American Express | Business | ⚑ New — number TBD | n/a | n/a |
| Diners Club | Consumer | `3608 280009 1007` | n/a | n/a |
| Diners Club | Business | ⚑ New — number TBD | n/a | n/a |

**Cards for specific flows**

| Use it to test | Card number | Notes |
| - | - | - |
| Native OTP: card that supports it | `4895 1911 1111 1115` | Used in CARD-B2 |
| Native OTP: card that doesn't support it | `4386 2894 0766 0153` | `/v1/payment/flows` returns `otp: false`; use 3DS |
| International card | `4012 8888 8888 1881` | — |
| International card with billing address | `5105 1051 0510 5100` | Asks for a billing address |
| Card EMI | `5241 8100 0000 0000` | — |

## 3. Scenarios to Test Your Integration

**Must-have (6)** — the paths where money moves or is lost: a successful payment, a decline, a cancel, a fetch-and-reconcile, and the 3DS redirect.

**Other common scenarios (8)** — refunds, Native OTP, saved cards and tokens, network tokens, Token HQ, one-time payments on a recurring token, and an IIN lookup.

**Error scenarios (6)** — failures you trigger deliberately with a test card, so you can check your error handling without waiting for a real one.

**Not available in test mode yet (5)** — real scenarios your integration still has to handle, but can't be reproduced here today.

25 scenarios in all: 20 you can run in test mode today, 5 you cannot.

### 3.1 Must-have

| Scenario ID | Method | Scenario | Trigger | Steps to follow |
| - | - | - | - | - |
| P01 | S2S JSON, S2S Redirect | Successful payment | `4100 2800 0000 1007`, any CVV, any future expiry + Success (or any 4–10 digit OTP) | Create an order. Create the payment. Complete authentication on the mock bank page. Verify the signature. Confirm `payment.captured` and `order.paid`. |
| P03 | All | Declined by bank | `4100 2800 0005 0004` + Failure | Pay with the card and choose Failure. Confirm `payment.failed` with `card_declined`. Let the customer try another card. |
| P04 | All | Customer cancels | `4100 2800 0007 0002` + Failure | Pay and choose Failure (or close the bank page). Confirm `payment_cancelled`. The order stays open for a retry. |
| P05 | All | Payment times out or session expires | `4100 2800 0009 0000`, `4100 2800 0003 0048` + Failure | Pay and choose Failure. Confirm `payment_timed_out` / `payment_session_expired`. Don't fulfil. |
| P10 | All | Fetch payment and reconcile | A payment ID from P01 (success) and one from P03 (failure) | Call `GET /v1/payments/:id` after each scenario. Confirm the status matches the webhook. Call it with a wrong ID and confirm the error. |
| CARD-B1 | S2S Redirect, S2S JSON | 3DS: redirect to the bank page | Any success card | Create the payment and redirect to `next[]` (JSON) or render the page (Redirect). Enter a 4–10 digit OTP; repeat with fewer than 4 digits. Confirm the customer returns to your `callback_url`. |

### 3.2 Other common scenarios

| Scenario ID | Method | Scenario | Trigger | Steps to follow |
| - | - | - | - | - |
| P12 | All | Full and partial refund | A captured payment from P01 | Refund one payment in full and one in part (`POST /v1/payments/:id/refund`). Confirm `refund.processed` and `refund_status`. |
| CARD-B2 | S2S JSON V2 (on-demand) | Native OTP: generate, submit, resend | `4895 1911 1111 1115` | Create the payment with `auth_type: "otp"`. Call `otp_generate`, then `otp/submit`. Submit a wrong OTP: expect `action: "RETRY"`. Then resend and submit again. |
| CARD-C1 | Saved cards | Save a card during payment | Any success card + `save: 1` + `customer_id` | Create a customer. Pay with `save: 1`. Confirm the token appears in `GET /v1/customers/:id/tokens`. |
| CARD-C2 | Saved cards | Pay with a saved token | Token from CARD-C1 + CVV | Pay with `customer_id` and `token`. Confirm success without the card number. |
| CARD-C3 | Token requestors | Pay with your own network token | Your network token + cryptogram | Create the payment with `card.tokenised: true`, `cryptogram_value`, `token_provider`. Leave out a field and confirm `input_validation_failed`. |
| CARD-C4 | Token HQ (on-demand) | Create, fetch and delete tokens | Valid and invalid token requests | Call `POST /v1/tokens`, `/tokens/fetch`, `/tokens/delete`. Send each invalid request. Confirm `token.activated` and `token.deactivated`. |
| CARD-C5 | Recurring + one-time | One-time payment on a recurring token | Token from a card mandate registration | Register a mandate. Create a new order and pay with `customer_id` + `token`, without `recurring`. Confirm the mandate stays active. |
| CARD-D1 | IIN API (on-demand) | Look up card details by IIN | `GET /v1/iins/410028`; invalid: `000000`, `41002` | Call the IIN API for a card IIN and a token IIN. Send each invalid IIN and confirm the error. |

### 3.3 Error scenarios

| Scenario ID | Method | Scenario | Trigger | Steps to follow |
| - | - | - | - | - |
| P02 | All | Insufficient funds | `4100 2800 0008 0001` + Failure | Pay and choose Failure. Confirm `insufficient_funds` and a "try another card" message. |
| P06 | All | Authentication fails | `4100 2800 0000 0009` + Failure, or an OTP under 4 digits | Pay and fail authentication. Confirm `error.step: "payment_authentication"`. |
| P07 | All | Bank technical error | `4100 2800 0007 0036` + Failure | Pay and choose Failure. Confirm `bank_technical_error` and a retry option. |
| P08 | All | Gateway technical error | `4100 2800 0002 0007`, or any test card + Failure | Pay and choose Failure. Confirm `gateway_technical_error`. |
| P09 | All | API validation errors | Missing `amount`, `amount: 0`, wrong key secret | Send each bad request. Confirm HTTP 4xx, no payment created, no webhook. |
| CARD-N1 | All | Network or international card not enabled | Amex `3402 560004 01007`, international `4012 8888 8888 1881` | Pay with each card while that network or international payments is disabled. Confirm `card_network_not_enabled` / `international_transaction_not_allowed`. |

### 3.4 Not available in test mode yet

| Scenario ID | Method | Scenario | Why it is not in test mode |
| - | - | - | - |
| CARD-X1 | All | Manual and partial capture | Coming soon · TBD. Check in a small live test. |
| CARD-X2 | Saved cards | CVV-less saved card payments | Coming soon · TBD. Check in a small live test. |
| CARD-X3 | Device tokens | Apple Pay, Card Sync (CRED, Google) | Coming soon · TBD. Check in a small live test. |
| CARD-X4 | Authentication | Visa and Mastercard passkeys | Coming soon · TBD. Check in a small live test. |
| CARD-X5 | Pricing | Customer fee bearer (convenience fee) | Coming soon · TBD. Check in a small live test. Changing fee bearer in test mode also changes it in live — be careful. |

## 4. Scenario Details

Each block follows the same format: before you start, how to test, expected result, webhooks, and errors to test.

### P01 — Successful card payment (covers P09, CARD-N1)

**Before you start:** an order created with `POST /v1/orders` (every payment needs an `order_id`). Test order creation once on [Orders](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md).

**How to test:** create the payment with the order's `order_id` and a success card from the test kit (for example Visa `4100 2800 0000 1007`) using S2S JSON (`POST /v1/payments/create/json`) or S2S Redirect (`POST /v1/payments/create/redirect`). Redirect the customer to the URL in `next[]` (JSON) or render the returned page (Redirect). On the mock bank page, enter any 4–10 digit OTP.

**Expected result:** payment `captured` (or `authorized` if you capture manually). The customer returns to your `callback_url` with `razorpay_payment_id`, `razorpay_order_id` and `razorpay_signature`; verify the signature server-side.

**Webhooks:** `payment.authorized`, `payment.captured`, `order.paid`

**Your integration should:** verify the signature server-side and fulfil on `payment.captured`.

### P04 — Customer cancels, times out or session expires (covers P05)

**How to test:** start a payment, then close the mock bank page or choose cancel. Use the cancel and timeout cards for the exact errors: `payment_cancelled` (`4100 2800 0007 0002`), `payment_timed_out` (`4100 2800 0009 0000`), `payment_session_expired` (`4100 2800 0003 0048`).

**Expected result:** the payment ends `failed`. The order stays unpaid so the customer can retry.

**Webhooks:** `payment.failed`

### P06 — Authentication failures

**How to test:** pay with each authentication-failure card and choose Failure: `4100 2800 0000 0009` (`authentication_failed`), `4100 2800 0004 0039` (`declined_by_bank`), `4100 2800 0004 0047` (`acs_maximum_attempts_reached`), `4100 2800 0002 0031` (`incorrect_pin`), `4100 2800 0005 0046` (`pin_attempts_exceeded`), `4100 2800 0004 0013` (`card_not_enrolled`).

**Expected result:** payment fails at `error.step: "payment_authentication"`. Ask the customer to retry or use another card.

**Webhooks:** `payment.failed`

### P10 — Fetch payment and reconcile

**How to test:** call `GET /v1/payments/:id` after each scenario above. Also call it with a wrong ID, and with a test-mode payment ID using live keys.

**Expected result:** the status matches the webhook you received. A wrong ID returns an error.

### CARD-B1 — 3DS: redirect to the bank page

**How to test:** pay with any success card. You're redirected to the mock bank page; any 4–10 digit OTP succeeds, an OTP under 4 digits fails the payment.

**Webhooks:** success `payment.authorized`, `payment.captured`, `order.paid`; failure `payment.failed`

### CARD-B2 — Native OTP: generate, submit and resend

**Before you start:** S2S JSON V2 enabled on your account (on-demand).

**How to test:** optionally check Native OTP support with `POST /v1/payment/flows`. Create the payment with `auth_type: "otp"` using a Native OTP card. Call `POST /v1/payments/:payment_id/otp_generate` (URL is in `next[]`). Submit the OTP with `POST /v1/payments/:payment_id/otp/submit`. Any 4–10 digit OTP succeeds in test mode. Test resend once with `otp/resend`, then submit again.

**Expected result:** `otp_generate` and `otp/resend` return `next[]` with `otp_submit` and `otp_resend`. A successful submit returns the signature fields.

**Webhooks:** success `payment.authorized`, `payment.captured`, `order.paid`. A wrong OTP that returns `action: "RETRY"` sends no webhook; `payment.failed` comes only when the payment finally fails.

**Your integration should:** treat `action: "RETRY"` as "ask again", not as a failure.

### CARD-C1 — Save a card during payment

**Before you start:** a customer created with `POST /v1/customers`.

**How to test:** pay with a success card, `save: 1` and `customer_id` on `POST /v1/payments/create/json`.

**Expected result:** payment succeeds and a token is created for the customer, visible in `GET /v1/customers/:customer_id/tokens`.

**Webhooks:** `payment.authorized`, `payment.captured`, `order.paid`. If you use Token HQ, also `token.initiated`, `token.activated`.

### CARD-C2 — Pay with a saved Razorpay token

**Before you start:** a token saved in CARD-C1.

**How to test:** pay again with `customer_id` and the token, plus the CVV.

**Expected result:** payment succeeds without the card number.

**Webhooks:** `payment.authorized`, `payment.captured`, `order.paid`

### CARD-C3 — Pay with your own network token

**Before you start:** you're a token requestor with a network token and cryptogram.

**How to test:** create the payment with `card.tokenised: true`, `cryptogram_value`, `token_provider` and `provider_type: "network"`.

**Webhooks:** `payment.authorized`, `payment.captured`, `order.paid`

### CARD-C4 — Create, fetch and delete tokens

**Before you start:** Token HQ enabled on your account for the `/v1/tokens` APIs.

**How to test:** Token HQ — call `POST /v1/tokens`, `POST /v1/tokens/fetch`, `POST /v1/tokens/delete`. Saved cards — call `GET /v1/customers/:customer_id/tokens`, `GET .../tokens/:token_id` and `DELETE .../tokens/:token_id`.

**Webhooks:** create `token.initiated`, `token.activated`. Delete `token.deactivated`. Sent by the network later: `token.expiry_updated`, `token.suspended`.

### CARD-C5 — One-time payment with a recurring token

**Before you start:** recurring payments enabled on your account, and a customer.

**How to test:** use this if you save cards through a recurring (mandate) registration and also charge the same token for one-time purchases. Register the mandate with `recurring: 1` and `customer_id`, using the recurring test card Visa `4718 6091 0820 4366`. Wait until the token is `confirmed`. For the one-time purchase, create a new order, then call `POST /v1/payments/create/json` with `customer_id` and `token`, without `recurring` (or `recurring: 0`). CVV is optional for tokenised cards. Complete authentication from `next[]` (3DS on the mock bank page, or Native OTP as in CARD-B2).

**Expected result:** the one-time payment succeeds like any saved-card payment: the customer authenticates, and no pre-debit notification is sent. The mandate and token stay active.

**Webhooks:** mandate registration — `payment.authorized` (carries `token_id`), then `token.confirmed` or `token.rejected`. One-time payment — `payment.authorized`, `payment.captured`, `order.paid`, and `order.notification.delivered` is not sent (note the `order.` prefix on the live-mode event name).

### CARD-D1 — Look up card details by IIN

**Before you start:** IIN API enabled on your account (on-demand).

**How to test:** call `GET /v1/iins/:iin` before creating the payment — for example to check card type, international, EMI or recurring eligibility, or Native OTP support. A 6-digit card IIN (for example `410028`) works for all networks. A 9-digit token IIN works for Visa, Mastercard and RuPay; a 6-digit token IIN works for Amex; Diners Club isn't supported. Then send invalid IINs: `000000` (doesn't exist), `41002` (wrong length).

### P12 — Full and partial refunds

**Before you start:** a captured payment from P01.

**How to test:** refund one captured payment in full and another in part, with `POST /v1/payments/:payment_id/refund`.

**Expected result:** you receive `refund.created` and `refund.processed`. The payment shows `refund_status` as `full` or `partial`.

**Webhooks:** `refund.created`, `refund.processed`, or `refund.failed` if the refund fails. Refund errors are covered on [Refunds](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/refunds.md).

## 5. Webhooks: What Fires, and What It Lets You Decide

Every scenario above delivers a specific set of events, in a specific order. This table is the one place that says which, and — the part that actually matters — what each one entitles you to do. Most integration bugs that reach production are not missing webhooks; they are acting on the wrong one.

| Scenario | What it is | Events, in order | What it lets you decide |
| - | - | - | - |
| P01 | Successful payment | `payment.authorized`, `payment.captured`, `order.paid` | Fulfil the order. |
| P03 | Declined by bank | `payment.failed` | Let the customer try another card. |
| P04 | Customer cancels, times out or session expires | `payment.failed` | Keep the order open for a retry. |
| CARD-B1 | 3DS redirect | success: `payment.authorized`, `payment.captured`, `order.paid`; failure: `payment.failed` | Fulfil only after `payment.captured`, never on the browser callback alone. |
| P12 | Full and partial refund | `refund.created`, `refund.processed` (or `refund.failed`) | Update `refund_status` only on `refund.processed`. |
| CARD-B2 | Native OTP: generate, submit, resend | success: `payment.authorized`, `payment.captured`, `order.paid`; a wrong OTP with `action: "RETRY"` sends nothing | Ask for the OTP again on `action: "RETRY"`; don't treat it as a failure. |
| CARD-C1 | Save a card during payment | `payment.authorized`, `payment.captured`, `order.paid`; with Token HQ also `token.initiated`, `token.activated` | Mark the saved card usable only after `token.activated`. |
| CARD-C2 to CARD-C5 | Pay with a saved card, network token or recurring token | `payment.authorized`, `payment.captured`, `order.paid` | Fulfil the same way as a fresh card payment. |
| P06 | Authentication fails | `payment.failed` | Ask the customer to retry or use another card. |

**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.
* **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.

## 6. Common Integration Gaps to Avoid

| Gap | What goes wrong in production | What to do | Test with |
| - | - | - | - |
| Showing raw codes | The customer sees `BAD_REQUEST_ERROR` and drops off. | Show `error.description`. It is written for the customer. | P02–P08 |
| Same message for every failure | A customer whose card was declined retries the same card again and again. | Branch on `error.reason` and `error.source`: ask for another card on issuer declines, ask to re-enter on wrong details, offer a plain retry on technical errors. | P02, P03, P07 |
| Wrong OTP treated as failure | With Native OTP, a wrong OTP returns `action: "RETRY"`, but the integration ends the payment. | On `incorrect_otp` with `action: "RETRY"`, show the OTP screen again with resend. | CARD-B2 |

### Webhook and token updates

| Gap | What goes wrong in production | What to do | Test with |
| - | - | - | - |
| Fulfilling on the checkout callback | The customer closes the bank page or loses network after paying. You never get the callback, so a paid order looks unpaid. | Fulfil on `payment.captured` or `order.paid`. Treat the callback as a hint, not proof. | P01 |
| Saved card marked usable too early | The card shows as saved but the first token payment fails because the network token isn't active yet. | Mark the card usable only after `token.activated`. Remove it on `token.deactivated`; update or hide it on `token.expiry_updated` and `token.suspended`. | CARD-C1, CARD-C4 |
| Duplicate or unsigned events processed | One payment fulfils twice, or a forged event marks an order paid. | Verify `X-Razorpay-Signature`. Store event IDs and skip repeats. | Webhooks |

### Fetch API when webhooks are late

| Gap | What goes wrong in production | What to do | Test with |
| - | - | - | - |
| Marking the order failed when nothing arrives | The bank responds slowly. You mark the order failed and the payment captures minutes later. | If no webhook arrives within a minute, poll `GET /v1/payments/:id` or `GET /v1/orders/:id/payments`. Treat the API as the source of truth. | P10 |
| No reconciliation job | Payments captured during a webhook outage never reach your system. | Run a periodic job that fetches orders still `attempted` and reconciles them. | P10 |

## 7. Best Integration Practices

These apply to every Razorpay integration. "On this method" says what each one means for cards; "Test it" links to where it is tested once for every method.

| Topic | What to know | On this method | Test it | Read more |
| - | - | - | - | - |
| Difference between order and payment | An order is what you want to collect. A payment is one attempt to pay it. One order can have many attempts but only one captured payment. Create the order on your server so the amount can't be tampered with. | A new order is needed for every payment attempt once the previous attempt has reached a terminal state. | BP-24, BP-25 | [Difference between order and payment ↗](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/order-payment-relationship.md) |
| Order states | Orders move `created` → `attempted` → `paid`. An order stays `attempted` through failed attempts, and stays `paid` even after a refund. | P10 fetches a payment to reconcile its status against the order. | [Payment states](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/payment-states-and-late-authorisation.md) · [Orders errors](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md) | [Order states ↗](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/payment-states-and-late-authorisation.md) · [Orders API error codes ↗](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md) |
| Late authorisation | A payment with no bank response is marked `failed` after 10 minutes, but Razorpay keeps polling the bank for 3 days. If the bank confirms, the payment becomes `authorized` (under 0.5% of payments). Listen for `payment.authorized` and capture it, or let it auto-refund. | BP-06 | BP-06 | [Late authorisation ↗](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/payment-states-and-late-authorisation.md) |
| Capture settings | Choose auto-capture or manual capture and set the timeouts. An `authorized` payment you don't capture in time is auto-refunded. | BP-14 covers manual and partial capture, coming soon for cards. | BP-14 | [Capture settings ↗](https://razorpay.com/docs/payments/payment-gateway/rainy-day/capture-settings) |
| Multiple payments on the same order | Once an order is `paid`, no more payments are accepted on it. While a payment on the order is `authorized`, a new attempt isn't allowed. | CARD-C5 pays a new order with a recurring token, never the same order twice. | BP-09 · BP-08 | [Multiple payments on the same order ↗](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/payment-states-and-late-authorisation.md) |

All best practices: [Overview](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices) · [Webhooks and Fetch APIs](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/webhooks-and-fetch-apis.md) · [Payment states and late authorisation](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/payment-states-and-late-authorisation.md) · [Error handling](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/error-handling.md) · [Downtime handling](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/downtime-handling.md) · [Security](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/security.md)

## 8. Simulate Failures

The full list of Cards error reasons, including the ones no trigger reproduces in test mode, is on the [Error index](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/error-handling.md). Branch your handling on `error.reason` and `error.source`, never on the `description` text. These are payment errors; errors from creating the order are on [Orders](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md).

### Errors available in test mode (33 triggers → 31 distinct error.reason values)

Grouped by source: Customer (19), Issuing bank (8), Bank (1), Gateway (2), Your request (business) (1), Razorpay internal (2), Source not mapped (1).

Pay with the card and choose Failure on the mock bank page.

| Trigger | error.code | error.source | error.step | error.reason | error.description |
| - | - | - | - | - | - |
| `4100 2800 0000 0009` + Failure | GATEWAY\_ERROR | customer | payment\_authentication | authentication\_failed | Your payment could not be completed due to incorrect OTP or verification details. Try another payment method or contact your bank for details. |
| `4100 2800 0007 0051` + Failure | BAD\_REQUEST\_ERROR | customer | — | card\_cvv\_invalid | You have entered an incorrect CVV number. Try again. |
| `4100 2800 0009 0034` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | card\_expired | Your payment could not be completed as your card has expired. Try another payment method. |
| `4100 2800 0004 0013` + Failure | GATEWAY\_ERROR | customer | card\_enrollment\_check | card\_not\_enrolled | Your payment could not be completed as this card is not enabled for online payments. Try another payment method or contact your bank for details. |
| `4100 2800 0001 0008` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | card\_number\_invalid | You've entered an incorrect card number. Try again. |
| `4100 2800 0001 0032` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | debit\_instrument\_blocked | Your payment could not be completed as your card is blocked. Try another payment method or contact your bank for details. |
| `4100 2800 0005 0038` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | debit\_instrument\_inactive | Your payment could not be completed as this card is not enabled for online payments. Try another payment method or contact your bank for details. |
| `4100 2800 0001 0040` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | incorrect\_card\_details | You've entered incorrect card details. Try again or retry the payment with another card or method. |
| `4100 2800 0002 0049` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | incorrect\_card\_expiry\_date | You've entered an incorrect expiration date. Try again. |
| `4100 2800 0000 0033` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | incorrect\_cvv | You've entered an incorrect CVV number. Try again. |
| `4100 2800 0002 0031` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | incorrect\_pin | Incorrect PIN entered. Please try again. |
| `4100 2800 0008 0001` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | insufficient\_funds | Your payment could not be completed due to insufficient account balance. Try another card or payment method. |
| `4100 2800 0007 0002` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | payment\_cancelled | Your payment has been cancelled. Try again or complete the payment later. |
| `4100 2800 0003 0048` + Failure | GATEWAY\_ERROR | customer | payment\_authentication | payment\_session\_expired | Your payment could not be completed on time. Try again later. |
| `4100 2800 0009 0000` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | payment\_timed\_out | Payment was not completed on time. |
| `4100 2800 0005 0046` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authentication | pin\_attempts\_exceeded | You've entered an incorrect pin too many times. Try again in sometime. |
| `4100 2800 0008 0043` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | transaction\_daily\_count\_exceeded | You've reached the maximum transaction limit on this card for today. Try another payment method or contact your bank. |
| `4100 2800 0009 0042` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | transaction\_daily\_limit\_exceeded | Payment failed because card has reached its limit. |
| `4100 2800 0008 0035` + Failure | BAD\_REQUEST\_ERROR | customer | payment\_authorization | transaction\_limit\_exceeded | You've reached the maximum transaction limit for this card. Try another payment method or contact your bank. |
| `4100 2800 0007 0036` + Failure | GATEWAY\_ERROR | issuer\_bank | payment\_authorization | bank\_technical\_error | Your payment did not go through due to a temporary technical issue at the bank. Any debited amount will be refunded in 4-5 business days. |
| `4100 2800 0006 0003` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authorization | card\_declined | Your payment didn't go through as it was declined by the bank. Try another payment method or contact your bank. |
| `4100 2800 0005 0004` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authorization | card\_declined | Your payment didn't go through as it was declined by the bank. Try another payment method or contact your bank. |
| `4100 2800 0004 0005` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_initiation | card\_declined | Your payment didn't go through as it was declined by the bank. Try another payment method or contact your bank. |
| `4100 2800 0003 0006` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authorization | card\_disabled\_for\_online\_payments | Your card has been disabled for online payments by your issuing bank. Please reach out to your bank or re-try with another card or method. |
| `4100 2800 0004 0039` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authentication | declined\_by\_bank | Your payment did not go through as it was declined by the bank. Try another payment method or contact your bank. |
| `4100 2800 0007 0044` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authorization | issuer\_declined | Transaction not supported/blocked by issuer. |
| `4100 2800 0003 0030` + Failure | BAD\_REQUEST\_ERROR | issuer\_bank | payment\_authorization | payment\_risk\_check\_failed | Your payment did not go through as it was declined by the bank. Try another payment method or contact your bank. |
| `4100 2800 0006 0045` + Failure | GATEWAY\_ERROR | bank | payment\_authorization | card\_restricted | Payment processing failed due to error at bank or wallet gateway. |
| `4100 2800 0002 0007` + Failure | GATEWAY\_ERROR | gateway | payment\_authorization | gateway\_technical\_error | Payment processing failed due to error at bank or wallet gateway. |
| `4100 2800 0006 0037` + Failure | BAD\_REQUEST\_ERROR | gateway | payment\_authorization | payment\_failed | Payment failed. |
| `4100 2800 0008 0050` + Failure | GATEWAY\_ERROR | business | payment\_authentication | card\_name\_invalid | Your payment could not be completed as the card holder name is not of correct format. Enter the card holder name in correct format or try with another card. |
| `4100 2800 0000 0041` + Failure | GATEWAY\_ERROR | internal | payment\_initiation | — | Your payment didn't go through due to a temporary issue. Any debited amount will be refunded in 4-5 business days. |
| `4100 2800 0004 0047` + Failure | BAD\_REQUEST\_ERROR | — | — | acs\_maximum\_attempts\_reached | Payment was unsuccessful as you exceeded the number of authentication attempts. |

### Errors not available in test mode (38 rows → 38 distinct error.reason values)

These happen on live card payments but can't be triggered here. Handle them by `error.reason` the same way. Grouped by source: Customer (1), Your request (business) (1), Razorpay internal (36), of which source not mapped (33). 17 mandate errors are left out of this count — simulate those on [Card recurring](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/recurring/card-recurring).

| error.code | error.source | error.step | error.reason | error.description |
| - | - | - | - | - |
| BAD\_REQUEST\_ERROR | customer | pre\_debit\_notification | token\_deleted | The requested token has been deleted |
| GATEWAY\_ERROR | business | payment\_initiation | token\_expired | Gateway Error Technical Error. |
| GATEWAY\_ERROR | internal | payment\_initiation | bin\_disabled | Your payment could not be completed as your card is not supported. Try another payment method. |
| SERVER\_ERROR | internal | payment\_creation | internal | The server encountered an error. The incident has been reported to admins. |
| SERVER\_ERROR | internal | get\_token | server\_error | Your payment could not be completed due to a temporary technical issue. To complete the payment, use another payment method. |
| BAD\_REQUEST\_ERROR | — | — | amount\_mismatch | The amount does not match with payment amount |
| BAD\_REQUEST\_ERROR | — | — | avs\_failure | Payment failed as it did not pass all risk checks. Please try again or use another card. |
| BAD\_REQUEST\_ERROR | — | — | bank\_account\_validation\_failed | Your payment is declined due to a mismatch in account details. Try again with the account registered with the business only. |
| BAD\_REQUEST\_ERROR | — | — | card\_bin\_not\_found | Card could not be processed. Please try a different card |
| BAD\_REQUEST\_ERROR | — | — | card\_not\_eligible | The card is not eligible for tokenisation. |
| BAD\_REQUEST\_ERROR | — | — | card\_read\_error | Card could not be read properly. Please try again |
| SERVER\_ERROR | — | — | cross\_border\_error | Error unmarshalling HTTP response |
| BAD\_REQUEST\_ERROR | — | — | decryption\_failed | Decryption failed |
| BAD\_REQUEST\_ERROR | — | — | duplicate\_transaction | This transaction has already been processed |
| BAD\_REQUEST\_ERROR | — | — | expired\_otp | Payment processing failed because of expired OTP |
| BAD\_REQUEST\_ERROR | — | — | fallback\_declined | Payment could not be processed. Please try again |
| BAD\_REQUEST\_ERROR | — | — | fees\_greater\_than\_amount | Invalid Fee |
| BAD\_REQUEST\_ERROR | — | — | giftcard\_limits\_exhausted | Your payment didn't go through as you have exhausted the Giftcard limits. You can buy more giftcards next cycle. |
| GATEWAY\_ERROR | — | — | incorrect\_cardholder\_name | You've entered an incorrect card name. Try again. |
| BAD\_REQUEST\_ERROR | — | — | incorrect\_request | Something went wrong, please try again after sometime. |
| BAD\_REQUEST\_ERROR | — | — | invalid\_data | Your payment didn't go through due to a temporary issue. Please reach out to the business. |
| BAD\_REQUEST\_ERROR | — | — | invalid\_iin | The requested IIN is not a valid token IIN |
| BAD\_REQUEST\_ERROR | — | — | invalid\_transaction | This transaction could not be processed. Please try again |
| BAD\_REQUEST\_ERROR | — | — | invalid\_txn\_id | The transaction id is invalid |
| BAD\_REQUEST\_ERROR | — | — | issuer\_special\_condition | Payment could not be processed. Please contact your card issuer |
| INTERNAL\_SERVER\_ERROR | — | — | key\_exchange\_failed | Payment could not be processed. Please try again |
| BAD\_REQUEST\_ERROR | — | — | NA | Could not validate payment callback request |
| BAD\_REQUEST\_ERROR | — | — | no\_checking\_account | No active checking account linked to the card. Contact your issuer or use another payment method. |
| BAD\_REQUEST\_ERROR | — | — | no\_saving\_account | No active savings account linked to the card. Contact your issuer or use another payment method. |
| BAD\_REQUEST\_ERROR | — | — | otp\_length\_invalid | Payment was unsuccessful as the OTP length is incorrect. Please submit a valid OTP with length of 4, 6 or 8 digits. |
| GATEWAY\_ERROR | — | payment\_authorization | — | Your payment didn't go through due to a temporary issue. Any debited amount will be refunded in 4-5 business days. |
| BAD\_REQUEST\_ERROR | — | — | pending\_confirmation | The transaction is pending final confirmation from the payment provider. |
| BAD\_REQUEST\_ERROR | — | — | pin\_required | PIN is required for this transaction. Please try again |
| INTERNAL\_SERVER\_ERROR | — | — | pricing\_not\_configured | Payment could not be processed. Please contact the merchant |
| GATEWAY\_ERROR | — | — | terminal\_error | Your payment could not be completed due to a temporary technical issue. To complete the payment, use another payment method. |
| BAD\_REQUEST\_ERROR | — | — | terminal\_not\_found | Payment could not be processed. Please contact the merchant |
| BAD\_REQUEST\_ERROR | — | — | tpv\_not\_enabled | Your payment was unsuccessful as this seller is not enabled for card payments. Try using another method. |
| GATEWAY\_ERROR | — | — | transaction\_frequency\_limit\_exceeded | Payment was unsuccessful as the number of transactions exceeds the max limit set by the bank. You can use another bank account or retry after some time. |

> [!NOTE]
>
> **Handy Tips**
>
> For a full picture of what fires when, see [Webhooks and Fetch APIs](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/webhooks-and-fetch-apis.md). Verify the signature on every event, key your handler on the event ID, and never assume event order.

### Related Information

* [Orders](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/orders.md)
* [Refunds](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/refunds.md)
* [Card recurring](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/recurring/card-recurring)
* [Best Practices](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices)
