Enable Apple Pay in Stripe by verifying your domain in the Stripe Dashboard, adding the Payment Request Button Element to your frontend, and handling the payment token. Users on supported Apple devices will see the Apple Pay option automatically without any additional code on the server side.
Adding Apple Pay to Your Stripe Integration
Apple Pay lets customers pay with a single tap or glance on supported Apple devices. Stripe handles all the complexity — you verify your domain, add the Payment Request Button Element, and Stripe automatically shows Apple Pay when the customer's browser and device support it. No separate Apple Developer account is needed for web payments.
Prerequisites
- A Stripe account with an active payment integration
- Your domain served over HTTPS
- Stripe.js loaded on your frontend
- A backend endpoint that creates a PaymentIntent
Step-by-step guide
Verify your domain in the Stripe Dashboard
Verify your domain in the Stripe Dashboard
Go to Stripe Dashboard → Settings → Payment methods → Apple Pay. Click 'Add new domain', enter your domain name, and download the verification file. Place the file at /.well-known/apple-developer-merchantid-domain-association on your web server.
Expected result: Your domain appears as 'Verified' in the Apple Pay settings of your Stripe Dashboard.
Create a PaymentIntent on the server
Create a PaymentIntent on the server
Your backend creates a PaymentIntent as usual. The Payment Request Button uses the same PaymentIntent flow — no special server-side code is needed for Apple Pay.
1// server.js2const express = require('express');3const Stripe = require('stripe');4const stripe = Stripe(process.env.STRIPE_SECRET_KEY);5const app = express();6app.use(express.json());78app.post('/api/create-payment-intent', async (req, res) => {9 const intent = await stripe.paymentIntents.create({10 amount: req.body.amount,11 currency: 'usd',12 automatic_payment_methods: { enabled: true }13 });14 res.json({ client_secret: intent.client_secret });15});1617app.listen(3001);Expected result: Your backend returns a client_secret that the frontend will use to confirm the payment.
Add the Payment Request Button to your frontend
Add the Payment Request Button to your frontend
Create a PaymentRequest object with the total amount and mount the Payment Request Button Element. Stripe will automatically show Apple Pay if the user's device supports it, or hide the button otherwise.
1const stripe = Stripe('pk_test_your_publishable_key');23const paymentRequest = stripe.paymentRequest({4 country: 'US',5 currency: 'usd',6 total: { label: 'Order total', amount: 2000 },7 requestPayerName: true,8 requestPayerEmail: true9});1011const elements = stripe.elements();12const prButton = elements.create('paymentRequestButton', {13 paymentRequest14});1516paymentRequest.canMakePayment().then(result => {17 if (result) {18 prButton.mount('#payment-request-button');19 } else {20 document.getElementById('payment-request-button').style.display = 'none';21 }22});Expected result: The Apple Pay button appears on supported devices. On unsupported devices the button container is hidden.
Handle the payment token
Handle the payment token
Listen for the paymentmethod event on the PaymentRequest. Confirm the PaymentIntent with the payment method ID and complete the payment.
1paymentRequest.on('paymentmethod', async (event) => {2 const res = await fetch('/api/create-payment-intent', {3 method: 'POST',4 headers: { 'Content-Type': 'application/json' },5 body: JSON.stringify({ amount: 2000 })6 });7 const { client_secret } = await res.json();89 const { error, paymentIntent } = await stripe.confirmCardPayment(10 client_secret,11 { payment_method: event.paymentMethod.id },12 { handleActions: false }13 );1415 if (error) {16 event.complete('fail');17 } else if (paymentIntent.status === 'requires_action') {18 const { error: confirmError } = await stripe.confirmCardPayment(client_secret);19 if (confirmError) {20 event.complete('fail');21 } else {22 event.complete('success');23 }24 } else {25 event.complete('success');26 }27});Expected result: Apple Pay sheet dismisses after successful payment. The PaymentIntent status changes to 'succeeded' in your Stripe Dashboard.
Test Apple Pay
Test Apple Pay
Apple Pay works in test mode when using test API keys. On Safari, you can test with a real Apple device that has a card in Wallet (Stripe will not charge it when using test keys). On Chrome, you can test with Google Pay using the test card 4242424242424242.
Expected result: The payment completes in test mode. The Stripe Dashboard shows the test payment with the payment method type 'apple_pay' or 'google_pay'.
Complete working example
1// apple-pay-checkout.js2// Complete Apple Pay integration with Stripe Payment Request Button34const stripe = Stripe('pk_test_your_publishable_key');56const paymentRequest = stripe.paymentRequest({7 country: 'US',8 currency: 'usd',9 total: {10 label: 'Order total',11 amount: 2000 // $20.00 in cents12 },13 requestPayerName: true,14 requestPayerEmail: true15});1617const elements = stripe.elements();18const prButton = elements.create('paymentRequestButton', {19 paymentRequest,20 style: {21 paymentRequestButton: {22 type: 'buy',23 theme: 'dark',24 height: '48px'25 }26 }27});2829// Mount button only if Apple Pay / Google Pay is available30paymentRequest.canMakePayment().then(result => {31 if (result) {32 prButton.mount('#payment-request-button');33 if (result.applePay) {34 console.log('Apple Pay is available');35 }36 } else {37 document.getElementById('payment-request-button').style.display = 'none';38 console.log('No wallet payment methods available');39 }40});4142// Handle payment43paymentRequest.on('paymentmethod', async (event) => {44 try {45 const res = await fetch('/api/create-payment-intent', {46 method: 'POST',47 headers: { 'Content-Type': 'application/json' },48 body: JSON.stringify({ amount: 2000 })49 });50 const { client_secret } = await res.json();5152 const { error, paymentIntent } = await stripe.confirmCardPayment(53 client_secret,54 { payment_method: event.paymentMethod.id },55 { handleActions: false }56 );5758 if (error) {59 event.complete('fail');60 return;61 }6263 if (paymentIntent.status === 'requires_action') {64 const { error: actionError } = await stripe.confirmCardPayment(client_secret);65 event.complete(actionError ? 'fail' : 'success');66 } else {67 event.complete('success');68 }69 } catch (err) {70 event.complete('fail');71 console.error('Payment failed:', err);72 }73});Common mistakes when enabling Apple Pay in Stripe
Why it's a problem: Forgetting to verify the domain in the Stripe Dashboard
How to avoid: Go to Dashboard → Settings → Payment methods → Apple Pay and add your domain. Download and host the verification file at /.well-known/apple-developer-merchantid-domain-association.
Why it's a problem: Testing Apple Pay on a non-Apple device or non-Safari browser
How to avoid: Apple Pay only works on Safari and Apple devices. Use Google Pay on Chrome for testing the same Payment Request Button flow.
Why it's a problem: Not calling event.complete() after handling the payment
How to avoid: Always call event.complete('success') or event.complete('fail') — otherwise the Apple Pay sheet stays open indefinitely.
Why it's a problem: Serving the page over HTTP instead of HTTPS
How to avoid: Apple Pay requires HTTPS. Use a tool like ngrok for local development to get an HTTPS URL.
Best practices
- Use automatic_payment_methods on the server so Apple Pay is enabled without listing payment methods manually
- Always check canMakePayment() before mounting the button to avoid showing it on unsupported devices
- Set requestPayerEmail and requestPayerName to collect customer info directly from the Apple Pay sheet
- Use the Payment Element instead of the Payment Request Button if you want a unified UI for all payment methods
- Test on real Apple devices with test mode enabled — Stripe will not create real charges with test keys
- Verify all domains where you serve the payment page, including staging and production
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to add Apple Pay to my Stripe checkout. Show me how to verify my domain, create a Payment Request Button with Stripe.js, handle the paymentmethod event, and confirm a PaymentIntent. Include the server-side code for creating the PaymentIntent.
Add an Apple Pay button to my checkout page using the Stripe Payment Request Button Element. Check canMakePayment, mount the button, and handle payment confirmation with confirmCardPayment. Show the complete frontend code.
Frequently asked questions
Do I need an Apple Developer account to accept Apple Pay with Stripe?
No. For web-based Apple Pay through Stripe, you only need to verify your domain in the Stripe Dashboard. An Apple Developer account is only needed for native iOS apps.
Can I test Apple Pay without a real Apple device?
Apple Pay specifically requires an Apple device with Safari. However, the Payment Request Button also supports Google Pay on Chrome, which you can test on any device with a test card.
What is the difference between Apple Pay and the Payment Request Button?
The Payment Request Button is a Stripe Element that automatically shows Apple Pay on Safari, Google Pay on Chrome, or Link on supported browsers. It is a single integration that covers multiple wallet payment methods.
Does Apple Pay work with Stripe Checkout?
Yes. If you use Stripe Checkout or Payment Links, Apple Pay is available automatically with no extra code. Domain verification is also handled for you.
Why does the Apple Pay button not appear on my page?
The button only appears if canMakePayment() returns a truthy result. This requires HTTPS, a verified domain, a supported browser (Safari), and a card configured in the Apple Wallet.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation