Integration Steps
Accept Apple Pay payments from international customers on your own checkout UI using the Razorpay Custom Checkout SDK.
Apple Pay is a secure, contactless payment method that lets customers pay using their Apple devices with Face ID/Touch ID authentication. With the Custom Checkout headless SDK, you check Apple Pay eligibility and either let Razorpay render the Apple Pay button or render your own — all on your existing Custom Checkout integration, with no redirect. Know more about
.This integration works with your existing card payment flow: check eligibility, render a button and initiate the payment with one additional app parameter.
- Accept payments in over 120 currencies from international customers.
- Reduce checkout time with one-touch biometric payments (Face ID/Touch ID).
- Full control of where and how the Apple Pay button appears on your page.
- Razorpay encapsulates device eligibility — no need to integrate the Apple Pay JS API or write capability-detection logic yourself.
- No need to handle Apple certificates or domain verification beyond hosting one file — Razorpay manages the rest.
Before you begin, ensure you have:
- An existing Razorpay Custom Checkout integration.
- Apple Pay enabled and International Payments enabled on your Razorpay account.
- HTTPS on your website — Apple Pay requires a secure context.
- Your API Key Id. Generate from the Dashboard. Use Live Mode keys to accept real payments.
- Apple Pay domain verification completed for your domain (host the domain association file; Razorpay registers it with Apple).
Follow the steps given below.
An order should be created for every payment.
- Create an order using the . This is a server-side call.
- Pass the returned
order_idto your frontend. This ties the order to the payment and secures the request from tampering.
Watch Out!
Payments made without an order_id cannot be captured and will be automatically refunded. Create an order before initiating payment.
curl -X POST https://api.razorpay.com/v1/orders \-u [YOUR_KEY_ID]:[YOUR_KEY_SECRET] \-H 'content-type:application/json' \-d '{"amount": 50000,"currency": "USD","receipt": "receipt_1"}'
The response includes an id (for example, order_XXXXXXXXXX). Pass this to your frontend for SDK initialisation. For the full list of order request and response parameters, see the
Include the Custom Checkout script, preferably in the <head> of your page:
<script type="text/javascript" src="https://checkout.razorpay.com/v1/razorpay.js"></script>
Handy Tips
Load the script from https://checkout.razorpay.com/v1/razorpay.js rather than serving a copy. This keeps updates and fixes automatic. Existing Custom Checkout merchants already load this script.
Initialise Razorpay with your key and the order_id created in step 1.1. Provide a handler to receive the successful payment response (you can also use event listeners — see step 1.6).
var razorpay = new Razorpay({key: 'rzp_live_xxx',order_id: 'order_XXXXXXXXXX', // created server-side at page loadcontact: '9123456789',email: 'gaurav.kumar@example.com',handler: function (response) {// response.razorpay_payment_id// response.razorpay_order_id// response.razorpay_signature // verify on your server}});
Use canMakePayment() to check whether the customer's device can pay with Apple Pay. Razorpay's SDK encapsulates the device capability check, so you do not integrate the Apple Pay JS API or evaluate paymentCredentialsAvailable yourself.
// canMakePayment() is async — call it inside an async function or a <script type="module">(async function () {var { available, reason } = await razorpay.canMakePayment({method: 'card',app: { name: 'apple_pay' },});// use `available` here — see step 1.5})();
The call resolves with available: true when the customer can pay with Apple Pay and false otherwise. Only render an Apple Pay button when available is true.
Note on Eligibility
canMakePayment() returns true for customers who can complete an Apple Pay payment on their current device and browser. For international customers, this includes devices where Apple Pay is set up and devices where the customer can add a card during the flow. For domestic (India) customers, it returns true only where a usable Apple Pay credential is already present. You do not need to handle these cases yourself — render the button whenever available is true.
Choose one of the following based on whether you want Razorpay to render the Apple Pay button or you render your own.
Listen for payment lifecycle events, consistent with Custom Checkout. (You may also use the handler function from step 1.3.)
razorpay.on('payment.success', function (response) {// response.razorpay_payment_id// response.razorpay_order_id// response.razorpay_signature // verify on your server});razorpay.on('payment.error', function (response) {// response.error.code// response.error.description// response.error.reason});
A successful payment returns:
{"razorpay_payment_id": "pay_29QQoUBi66xm2f","razorpay_order_id": "order_9A33XWu170gUtm","razorpay_signature": "9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d"}
Store these fields on your server and verify the payment signature (step 1.7).
A failed payment returns an error object:
{"error": {"code": "BAD_REQUEST_ERROR","description": "Customer cancelled the Apple Pay sheet or did not authenticate in time.","field": null,"source": "customer","step": "payment_authentication","reason": "payment_cancelled","metadata": {"payment_id": "pay_EDNBKIP31Y4jl8","order_id": "order_DBJKIP31Y4jl8","method": "card","app": "apple_pay"}}}
For the full list of error responses — canMakePayment() reasons, payment errors, client errors and a handling guide — see
Verify the signature on your server before fulfilling the order.
- Use the
order_idfrom your server (not therazorpay_order_idreturned by Checkout), therazorpay_payment_idfrom the response and yourkey_secret. - Construct an HMAC SHA256 hex digest:
generated_signature = hmac_sha256(order_id + "|" + razorpay_payment_id, secret);if (generated_signature == razorpay_signature) {// payment is successful}
- If the generated signature matches
razorpay_signature, the payment is authentic.
Sample verification (Node.js and other languages) is available in the
.Handy Tips
On the Razorpay Dashboard, ensure the payment status is captured. See
to capture payments automatically.You can track payment status in three ways: from the Dashboard (Transactions → Payments), by subscribing to webhook events or by polling the APIs.
// SDK init — order created server-side at page loadvar razorpay = new Razorpay({key: 'rzp_live_xxx',order_id: 'order_XXXXXXXXXX',contact: '9123456789',email: 'gaurav.kumar@example.com',handler: function (response) {// verify response.razorpay_signature on your server}});// Register event listeners before the async eligibility checkrazorpay.on('payment.success', function (response) { /* store + verify */ });razorpay.on('payment.error', function (response) { /* handle failure */ });var { available, reason } = await razorpay.canMakePayment({method: 'card',app: { name: 'apple_pay' },});if (available) {// Option A: Razorpay renders the buttonrazorpay.mount({method: 'card',app: { name: 'apple_pay' },container: document.getElementById('apple-pay-container'),theme: {themeColor: '#528FF0',buttonTheme: 'dark',buttonLabel: 'pay',},});// Option B (alternative): you render your own button// document.getElementById('my-apple-pay-btn').style.display = 'block';// document.getElementById('my-apple-pay-btn').addEventListener('click', function () {// razorpay.createPayment({// order_id: 'order_XXXXXXXXXX'// method: 'card',// app: { name: 'apple_pay' },// });// });}})();
No. canMakePayment() encapsulates the device capability check. You do not integrate the Apple Pay JS API or evaluate paymentCredentialsAvailable / paymentCredentialStatusUnknown yourself.
Render it only when canMakePayment() resolves with available: true.
Yes. On a retryable error (for example, network_timeout), retry with the same order_id — no duplicate payment is created until the previous attempt resolves.
Is this integration guide useful?
ON THIS PAGE