Available in🇮🇳 India
Every payment on Razorpay starts with an order created on your server. This page holds every order scenario: creating orders, the order lifecycle, idempotent retries and request validation. Method pages link here instead of repeating them.
Start with the overview for test keys and webhook setup.
1. Test Mode Coverage
Test your order integration with test keys. There are no special test credentials: the outcome depends on the request you send. Start from the request in the test kit, then change one field at a time using the triggers in Simulate Failures.2. Test Kit
There are no special test credentials: the outcome depends on the request you send. Start from this valid request, then change one field at a time using the triggers in Simulate Failures.3. Scenarios to Test Your Integration
25 scenarios · 21 available in test mode.4. Scenario Details
ORD-01 Create an order
Before you start Test keys. How to test Send the request in the test kit withamount: 100.
Expected result HTTP 200 with id (order_…), status: created, amount_due = amount, amount_paid: 0, attempts: 0.
Webhooks None. Orders fire order.paid only when paid.
Your integration should Create the order on your server, store id against your own receipt, and pass only the order_id to the client.
ORD-02 · ORD-03 Order lifecycle
Before you start An order from ORD-01 and a method page’s test triggers. How to test- Fail one payment on the order using a method’s failure trigger.
- Fetch the order:
status: attempted,attempts: 1. - Pay successfully using a method’s success trigger.
- Fetch the order:
status: paid,amount_paid = amount.
created → attempted → paid. The order stays paid even after a refund.
Webhooks payment.failed, then payment.captured and order.paid.
Your integration should Fulfil on order.paid or payment.captured, never on the checkout callback alone.
Watch out Reuse the order ID when the same cart is retried after a payment failure. Order IDs should be unique for each checkout session: create a new order only for a new checkout session, such as a new cart.
ORD-05 Idempotent create with unique_receipt
Before you start Test keys.
How to test Send unique_receipt: true with receipt: "r-123" twice.
Expected result Both calls return the same order ID.
Your integration should Use unique_receipt whenever you might retry a create (timeouts, 5xx), so a retry cannot create two orders for one cart.
How receipt uniqueness works
- Razorpay checks that
receiptis unique only when you sendunique_receipt: true, or when Razorpay has turned on receipt uniqueness for your account. - With
unique_receipt: true, a receipt you already used returns the existing order with HTTP 200. Retrying a create is safe. - If uniqueness is on for your account and you do not send
unique_receipt: true, a receipt you already used fails with HTTP 400Order receipt should be unique., andmetadata.order_idholds the existing order’s ID. - Only orders created while uniqueness was on are checked, and only for 180 days. A receipt used on an order created without it does not count. Test mode and live mode are checked separately.
- Two creates with the same receipt at the same moment are handled one at a time. The second can fail with
Another request in progress for the same process.; retry it and you get the existing order back.
ORD-07 Pay an order that is already paid
Before you start A paid order from ORD-02. How to test Start another payment with the sameorder_id.
Expected result The payment is declined with order_already_paid: “Your payment has been declined as the order is already paid. Please initiate the payment with a new order.”
Your integration should Check the order status before showing checkout again. Create a new order for a new purchase.
ORD-18 · ORD-19 UPI Autopay authorisation order (registration)
Before you start A customer (POST /v1/customers).
How to test Create the order with amount: 100, currency: "INR", method: "upi", customer_id and token: {max_amount, frequency, expire_at}. Then send each bad token below.
Expected result The valid order is created. Each bad request fails with the error below.
Your integration should Validate max_amount against your MCC limit and keep frequency to how you really bill before calling the API.
Errors to test
ORD-20 · ORD-21 Card mandate authorisation order
Before you start A customer. How to test Create the authorisation order for a card mandate withcustomer_id and a token object, then send each bad request below.
Expected result The valid order is created. Each bad request fails with the error below.
Errors to test
ORD-22 · ORD-23 Debit orders (subsequent debits)
Before you start A confirmed token. How to test- Create a new order for each debit, with its own
receipt. - Reuse a paid debit order.
- Debit twice in one billing cycle.
- UPI decoupled: add
notification: {token_id, payment_after}and try to debit early, or above the notified amount.
The 25-hour pre-debit-notification-to-debit window is enforced in test mode — it is a hardcoded NPCI rule, so a decoupled debit created inside the window is rejected. The 26-hour mandate-expiry rule is live-only.
5. 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
6. 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.7. Simulate Failures
To test request validation, send the valid request from the test kit and change one field at a time to an invalid value (see the rules column). Each invalid request returns HTTP 400 with an error object.- Branch your handling on
error.reasonanderror.source, never on thedescriptiontext. - Sanitise
receipt,notesanddescriptionbefore you call the API. - Log validation errors — do not surface them to the payer as a payment failure.
reasontells you what went wrong. Build your error handling on it; it is stable.descriptionis a human-readable message. It can change, so do not match on its text in code.sourcetells you who needs to act:businessmeans your request needs fixing;internalmeans a problem at Razorpay, so retry.steptells you where in the flow the error happened.field, when present, names the request parameter that caused the error.- The HTTP status tells you whether to retry: 4xx means fix the request first (retrying the same request fails again); 5xx means retry with exponential backoff.
- Take the
reasonfrom the error response and find it in the tables below. - To reproduce it in test mode, send the input in the Trigger column with test keys.
- Fix the field named in
error.field, when present, and retry.
Errors available in test mode (34 triggers → 7 distinct error.reason values)
Send the input in the Trigger column with test keys. Every one fails before an order is created, so nothing reaches the payer: log it and fix the request. Retrying the same request fails again.
Errors not available in test mode (15 rows → 8 distinct error.reason values)
These come from Razorpay’s side or from live-account conditions. On 5xx, retry with exponential back-off; with unique_receipt a retry will not create a duplicate order.