Magic Checkout Integration Guide

Complete end-to-end guide to integrate Razorpay Magic Checkout. Set up promotions and shipping APIs, accept COD, verify payments and go live safely.


This is a complete, end-to-end guide to accept payments using Razorpay Magic Checkout, the one-click checkout that prefills saved addresses and payment details, supports coupons and discounts, and accepts both prepaid and Cash on Delivery (COD) orders. Magic Checkout reduces COD return-to-origin (RTO) by analysing customer shopping history and address quality.

Once you finish integrating Razorpay using this guide, you will be able to accept payments from your customers using Magic Checkout. To see how this compares with the other integration options, refer to the

.

What you are responsible for:

  • Enabling the Magic Checkout feature on your account.
  • Hosting the promotions and shipping-info APIs that Magic Checkout calls.
  • Creating an order before payment.
  • Opening Magic Checkout with one_click_checkout: true.
  • Verifying the signature on your server.
  • Handling prepaid and COD fulfilment via webhooks.

Customer Magic Checkout Your Server Razorpay
| | | |
| | | 1. POST /v1/orders |
| | |-------------------->|
| | | order_id |
| 2. Open checkout | |<--------------------|
|------------------->| 3. get-promotions | |
| |----------------------->| (your API) |
| | 4. shipping-info | |
| |----------------------->| (your API) |
| 5a. Prepaid pay | | |
|------------------->|--------------------------------------------->| authorize
| 5b. Place COD | | |
|------------------->|--------------------------------------------->| order.placed
| | 6. success response | |
| |----------------------->| 7. Verify signature |
| | | 8. Capture (prepaid)|
| | |-------------------->|
| | | 9. Webhooks: |
| | | order.paid / |
| | | payment.pending / |
| | | fulfillment.* |
| | |<--------------------|
  1. Set up promotions and shipping APIs on your server and register them in the Dashboard (Step 1).
  2. Create an order for every checkout (Step 2).
  3. Open Magic Checkout with one_click_checkout: true; it calls your promotions and shipping APIs (Step 3).
  4. Verify the signature on your server for prepaid payments (Step 4).
  5. Confirm and fulfil via webhooks; capture prepaid payments and process COD orders (Step 5).

Use Magic Checkout when you run an ecommerce store and want a faster, one-click checkout with prefilled customer details, built-in coupons and COD support. If you only need to accept a payment and do not need addresses, coupons or COD, use

. If your store runs on WooCommerce or Shopify, use the or plugin instead of building this integration.

Handy Tips: Magic Checkout is an on-demand feature

Raise a request with your Razorpay SPOC or

to enable Magic Checkout and the Cash on Delivery payment method on your account.

Magic Checkout supports prepaid and COD orders, so it has an extra pending state for COD. You can fetch the current state with the

.

  • A with Magic Checkout enabled by your SPOC.
  • from the Dashboard. Use Test Mode keys while building and Live Mode keys to go live.
  • A server-side backend to call the Orders API, host the promotions and shipping APIs, and verify signatures.
  • HTTPS on your website with a valid SSL/TLS certificate.

Magic Checkout calls APIs on your server to fetch promotions and shipping information. Build these first and register their URLs in the Dashboard.

Watch Out: These URLs must be public and unauthenticated

The promotions and shipping-info URLs must be publicly accessible, require no authentication and be hosted on your server.

  1. Log in to the Dashboard and go to Magic Checkout.
  2. In Platform Setup, select Custom E-Commerce Platform and select Next.
  3. In Setup & Settings → Checkout Settings → Coupon Settings, enter the URL for get promotions and the URL for apply promotions, then save.
  4. Go to Shipping Setup, select API as the shipping service type, enter the URL for shipping info and save.

This API returns shipping serviceability, COD serviceability, shipping fees and COD fees for a list of customer addresses.

{
"order_id": "SomeReceiptValue",
"razorpay_order_id": "EKwxwAgItmXXXX",
"email": "alex.lim@example.com",
"contact": "+919000090000",
"addresses": [{ "id": "0", "zipcode": "560060", "state_code": "KA", "country": "IN" }]
}

Fees are in paise. If cod is false, set cod_fee to 0.

Before the promotions APIs can return anything, the promotions themselves must exist. You have two options:

  • Create coupons on the Razorpay Dashboard. Go to Magic Checkout → Setup & Settings → Coupon Settings and create coupons with a code, type (fixed_amount, percentage or BXGY), value and conditions such as minimum cart value or customer eligibility. Use this when you want Razorpay to manage coupon storage.
  • Manage promotions in your own system. Keep coupons in your commerce backend and have your get-promotions and apply-promotions APIs return them. Use this when your promotion logic (bundles, loyalty, personalised offers) already lives on your server.

Either way, Magic Checkout only ever reads promotions through the two APIs below, so they must always return the correct, current set.

The get-promotions API returns the coupons applicable to an order and customer. The apply-promotions API validates a code the customer enters and returns the discount.

{
"order_id": "SomeReceiptValue",
"contact": "+919000090000",
"email": "alex.lim@example.com"
}
{
"order_id": "SomeReceiptValue",
"contact": "+919000090000",
"email": "alex.lim@example.com",
"code": "500OFF"
}

The value is always in paise and applied as-is. value_type can be fixed_amount, percentage or BXGY (Buy X Get Y).

Create an order on your server for every checkout, the same as other Razorpay integrations. Save the id from the response and pass it to Magic Checkout in Step 3. Amounts are in paise, for example, ₹450 = 45000.

Watch Out: Set the final payable amount on the order

The amount the customer is charged is always the order amount, not anything passed on the client. Create the order with the final payable amount after any coupon or pre-discount, and never create orders in browser-side code.

curl -X POST https://api.razorpay.com/v1/orders \
-u [YOUR_KEY_ID]:[YOUR_KEY_SECRET] \
-H 'content-type:application/json' \
-d '{
"amount": 45000,
"currency": "INR",
"receipt": "rcptid_11"
}'

The receipt value you set here is the order_id your promotions and shipping APIs receive. Know more about the

.

Load magic-checkout.js and open Checkout with one_click_checkout: true. Use the handler function for SPAs or the callback URL for server-rendered apps.

<button id="rzp-button1">Pay</button>
<script src="https://checkout.razorpay.com/v1/magic-checkout.js"></script>
<script>
var options = {
"key": "YOUR_KEY_ID",
"one_click_checkout": true,
"name": "Acme Corp",
"order_id": "order_EKwxwAgItmXXXX", // from Step 2
"show_coupons": true, // set false to hide the coupon widget
"handler": function (response){
// send these three fields to your server for verification (Step 4)
alert(response.razorpay_payment_id);
alert(response.razorpay_order_id);
alert(response.razorpay_signature);
},
"prefill": {
"name": "Alex Lim",
"email": "alex.lim@example.com",
"contact": "9000090000",
"coupon_code": "500OFF" // auto-applied when Magic opens
},
"notes": { "address": "ABC Office" }
};
var rzp1 = new Razorpay(options);
rzp1.on('payment.failed', function (response){
alert(response.error.code);
alert(response.error.description);
alert(response.error.reason);
});
document.getElementById('rzp-button1').onclick = function(e){
rzp1.open();
e.preventDefault();
}
</script>

For server-rendered apps, set "callback_url": "https://yourserver.com/callback" and "redirect": "true" instead of the handler function.

For the complete list, see the full

.

Handy Tips: Pre-discounts and promotional tags

Use prefill.prediscount to display existing discounts (coupons, gift cards, loyalty points) in the order summary. Pre-discounts are display only and do not change the payment amount, which is always set by your Razorpay order. For gift cards, include gift_card_applied: true. Use prefill.promotional_tag to badge specific products.

Verify the signature on your server before fulfilling, exactly as in other Razorpay integrations. The signature is an HMAC-SHA256 hash of order_id and payment_id, signed with your Key Secret.

const crypto = require('crypto');
function verifyPaymentSignature(orderId, paymentId, receivedSig, keySecret) {
const body = orderId + '|' + paymentId;
const expectedSig = crypto
.createHmac('sha256', keySecret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSig, 'hex'),
Buffer.from(receivedSig, 'hex')
);
}
// Use the order_id from YOUR database, not the one from the browser.

Watch Out: Always verify the signature server-side

Use the order_id from your own database, not the one returned in the browser, which could be spoofed. Use a timing-safe comparison and store all three fields for audit and idempotency. A failed check means a tampered payment, so reject it.

Magic Checkout handles prepaid and COD orders, so subscribe to order, payment and fulfilment webhooks.

in Dashboard → Account & Settings → Webhooks, verify the X-Razorpay-Signature header on every event, return HTTP 200 within 5 seconds and process events in a background worker.

The confirmation path is different for prepaid and COD orders:

Handy Tips: COD is webhook-driven, not API-driven

You do not capture or "confirm" a COD payment with an API call. Razorpay confirms the COD order itself (including COD OTP and RTO scoring) and notifies you with order.placed and payment.pending. Your only job is to act on the fulfilment webhooks. The COD payment stays pending until you mark it delivered, and you update fulfilment status as the shipment progresses.

Order events

Payment events

Fulfilment events

For the full async webhook handler pattern, replay-attack guard, idempotency, monitoring metrics, rollback plan and logging strategy, see the shared deep-dives in the

. They apply to Magic Checkout too.

Handy Tips: Track the checkout funnel

Magic Checkout emits analytics events you can subscribe to with rzp1.on('mx-analytics', ...), including initiate, otp_initiated, payment_initiated, coupon_applied, payment_failed and checkout_abandoned. Forward these to your analytics platform to optimise conversion.

Test with Test Mode API keys so no real money moves. Use the mock bank page's Success and Failure buttons to simulate outcomes, and place a COD order to exercise the order.placed and payment.pending webhooks.

Use any random CVV and any future expiry date. For netbanking and wallets, choose any bank or wallet and use the Success or Failure buttons. See the full list of

.

  • The prepaid flow end to end, including signature verification and capture.
  • The COD flow: placing a COD order and receiving order.placed and payment.pending.
  • Coupon application through your get-promotions and apply-promotions APIs.
  • Shipping-info responses for serviceable, non-serviceable and COD-disabled pincodes.

  • If you configured settings in Test Mode, replicate them in Live Mode, including the promotions and shipping URLs.
  • Use API keys generated in Live Mode. If you have multiple Razorpay accounts, use the Live key from the account you intend to go live with.
  • Verify the signature server-side, fulfil only after capture (for prepaid) or after order.placed (for COD), and handle all subscribed webhooks idempotently.
  • Re-test the prepaid flow, the COD flow, coupon application and the shipping-info responses in Test Mode before switching keys.

What is Magic Checkout and how is it different from Standard Checkout?

Magic Checkout is Razorpay's one-click checkout. It prefills saved customer addresses and payment details, supports coupons and discounts, and accepts both prepaid and Cash on Delivery orders, with RTO intelligence to reduce COD returns. Standard Checkout only collects a payment. Magic Checkout loads magic-checkout.js and is opened with one_click_checkout: true, and it requires you to host promotions and shipping-info APIs.

Why do I need to host promotions and shipping APIs?

Magic Checkout calls your server to fetch applicable coupons, validate applied codes and determine shipping and COD serviceability and fees for the customer's address. These endpoints must be publicly accessible and unauthenticated, and you register their URLs in the Dashboard under Magic Checkout settings.

How do I handle Cash on Delivery orders?

COD orders move the payment to the pending state and fire order.placed and payment.pending webhooks. Confirm and process these through the fulfilment events (fulfillment.to_be_shipped through fulfillment.delivered). Enable the COD payment method by raising a request with Razorpay Support.

Do pre-discounts change the amount the customer pays?

No. Pre-discounts passed in prefill.prediscount are for display only. The amount charged is always determined by your Razorpay order, so create the order with the final payable amount. For gift cards, include gift_card_applied: true for correct tracking and display.

How long do I have to capture an authorised Magic Checkout payment?

An authorized payment moves to failed if it is not captured within 45 days. Capture it, or enable auto-capture, to confirm the payment and move it to captured before you fulfil. This applies to prepaid orders only; COD orders are not captured.

What are the most common Magic Checkout integration mistakes to avoid?

  • Promotions or shipping URLs behind authentication. They must be public and unauthenticated, or Magic Checkout cannot call them and the coupon and shipping widgets fail.
  • Returning order_id mismatches. Your APIs receive the order's receipt value as order_id. Make sure your server maps it correctly.
  • Expecting a COD capture step. COD is webhook-driven. Do not wait for a capture that never comes; act on order.placed.
  • Trusting the client amount. The charge is always the order amount. Create the order with the final payable amount after discounts.
  • Not replicating settings in Live Mode. Promotions and shipping URLs configured in Test Mode do not carry over automatically.
  • Fees in the wrong unit. All fees and discount values are in paise. cod_fee must be 0 when cod is false.
  • Parsing the webhook before verifying the signature. Verify against the raw body first.

Can I integrate Magic Checkout on mobile apps?

Yes. Besides the web SDK, Magic Checkout is available for

, , and . Order creation, promotions, shipping APIs and signature verification stay on your server and are identical across platforms.


Is this integration guide useful?


magic checkout
1cc
cash on delivery
coupons
one click checkout integration