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

# Retries and Idempotency

> Make every retried call safe to repeat, using unique_receipt on orders, the same order on retried payments and idempotency keys on refunds.

Available in
🇮🇳 India

Every call you might retry must be safe to repeat. Create an order with `unique_receipt: true` so a retried create returns the same order instead of a duplicate. Retry a payment on the same order so a customer cannot pay twice.

| Call | If it times out | Safe because |
| - | - | - |
| Create order | Retry with the same `receipt`. | Your receipt identifies the purchase. |
| Create payment | Fetch the order's payments first, then retry on the same order. | A paid order cannot take a second successful payment. |
| Create refund | Retry with the same `X-Refund-Idempotency` header. | Same key, same refund. The key must be at least 10 characters. |
| Webhook received twice | Ignore the repeat. | Check the `x-razorpay-event-id` header. |

## Scenarios to test your integration

| Scenario ID | Area | Scenario | Trigger | Steps to follow | Test mode |
| - | - | - | - | - | - |
| BP-07 | Retries and idempotency | Create order times out | Same `receipt` (with `unique_receipt: true`) | Drop the create-order response and retry with the same `receipt`. Confirm one order. See ORD-05. | Available |
| BP-08 | Retries and idempotency | Create payment times out | Drop the response of a create-payment call | Fetch the order's payments first. Retry on the same order only if no payment is in progress or captured. Confirm one captured payment. | Available |
| BP-12 | Retries and idempotency | Refund times out | Same `X-Refund-Idempotency` key (10+ characters) twice | Refund a captured payment twice with the same key. Confirm one refund and `refund.processed`. | Available |

> [!NOTE]
>
> **Open questions**
>
> Fetching the order's payments before retrying a create-payment call (BP-08) assumes you retry on the *same* order; confirm this matches your integration if you create a new order per attempt instead. Idempotency keys on refunds (BP-12) are not yet confirmed to work in Test Mode — verify before you rely on this behaviour.

## 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 |
| - | - | - | - |
| BP-12 | Refund times out | `refund.processed` | The money has left Razorpay. This is when you confirm the refund to the customer. |

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

### Related Information

* [Best Practices](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices)
* [Error Handling](https://razorpay.com/docs/payments/payment-gateway/s2s-integration/test-s2s/best-practices/error-handling.md)
* [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)
