Skip to main content
Available in🇮🇳 India
Refunds are always issued against an existing captured payment, so you create a test payment and then refund it. The refund amount decides the outcome. Specific amounts may fail and all others succeed. Whether a refund is Normal or Instant depends on the Refund Instantly checkbox, not the amount. Everything runs on your test keys and is fully simulated. No real money moves.

1. Test Mode Coverage

2. Test Kit

You need a captured test payment to refund. Payment first, then refund: a refund always acts on an existing captured payment, so your end-to-end flow is to create and capture a test payment, then refund it.
  • Create a test payment on an order and capture it, see Orders and the method pages, then capture with the Capture Payment API (POST /v1/payments/:id/capture).
  • Keep the payment amount greater than the refund amount. Capture more than ₹24.68 so one payment covers every case, including the ₹24.68 failure.
  • Refund it with POST /v1/payments/:id/refund (see the scenarios below).

3. Scenarios to Test Your Integration

Grouped into must-have refund flows, other common refund flows, and error scenarios. Click a Scenario ID for its details.

3.1 Must-have refund scenarios

Scenario IDScenarioTrigger credsSteps to follow
RFND-01Create a Normal refund (success)A captured payment, any refund amount (e.g. amount: 100), at speed: “normal”POST /v1/payments/:id/refund with test keys, amount: 100 and speed: “normal”. Confirm it moves from pending to processed, with speed_processed: “normal”. Store the refund id against your payment or order.
RFND-02Normal refund fails (coming soon)A captured payment above ₹24.68, amount: 2468 (₹24.68) at speed: “normal”POST /v1/payments/:id/refund with amount: 2468 and speed: “normal”. Confirm it moves from pending to failed. Handle the refund.failed webhook and reconcile.

3.2 Other common refund scenarios

Scenario IDScenarioTrigger credsSteps to follow
RFND-03Create an Instant refund (success) (coming soon)A captured payment, any refund amount (e.g. amount: 100), at speed: “optimum”POST /v1/payments/:id/refund with amount: 100 and speed: “optimum”. Confirm speed_requested: “optimum”, speed_processed: “instant”, and it moves from pending to processed. The per-refund fee is deducted from your test balance.
RFND-04Instant refund falls back to NormalA captured payment above ₹14.68, amount: 1468 (₹14.68) at speed: “optimum”POST /v1/payments/:id/refund with amount: 1468 and speed: “optimum”. Confirm it moves from pending to processed with speed_requested: “optimum” and speed_processed: “normal”. The instant fee is credited back to your test balance.
Seeing the pending stateWhether you see the pending refund state depends on your account. It is enabled by default for merchants onboarded on or after 28 April 2026, and for some onboarded earlier. If it isn’t enabled for your account, a refund appears directly as processed (or failed), without a visible pending state.

3.3 Refund error scenarios

Trigger each with a bad request and read the error object to handle it.

4. Scenario Details

RFND-01: Create a Normal refund (success) Before you start: a captured test payment and your test API keys. How to test: POST /v1/payments/:id/refund with amount: 100 and speed: "normal". Expected result: HTTP 200 with a refund ID (rfnd_…); it moves from pending to processed, with speed_processed: "normal". Webhooks: refund.created, then refund.processed. Your integration should: mark the refund successful on the processed state or the refund.processed webhook, and store the refund ID. RFND-02: Normal refund fails Before you start: a captured test payment greater than ₹24.68. How to test: POST /v1/payments/:id/refund with amount: 2468 (₹24.68) and speed: "normal". Expected result: the refund moves from pending to failed. Webhooks: refund.created, then refund.failed. Your integration should: handle the failed state / refund.failed webhook, and retry or reconcile. RFND-03: Create an Instant refund (success) Before you start: a captured test payment, with Instant Refunds enabled on your test account. How to test: POST /v1/payments/:id/refund with amount: 100 and speed: "optimum". Expected result: speed_requested: "optimum", speed_processed: "instant"; it moves from pending to processed. The per-refund fee is deducted from your test balance. Webhooks: refund.created, then refund.processed. Your integration should: read speed_processed = instant and account for the instant-refund fee. RFND-04: Instant refund falls back to Normal Before you start: a captured test payment greater than ₹14.68. How to test: POST /v1/payments/:id/refund with amount: 1468 (₹14.68) and speed: "optimum". Expected result: the instant refund cannot be processed instantly, so it falls back to normal speed. It moves from pending to processed with speed_requested: "optimum" and speed_processed: "normal"; the instant fee is credited back. Webhooks: refund.created, refund.speed_changed, then refund.processed. Your integration should: not assume instant always succeeds. Listen for refund.speed_changed, read speed_processed, and show the normal 5-7 working day timeline.

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.

6. Common Integration Gaps to Avoid

Last modified on November 12, 2026