# How to enable Apple Pay in Stripe

- Tool: Stripe
- Difficulty: Beginner
- Time required: 15 minutes
- Compatibility: Stripe.js v3, Safari 10+, iOS 10+, macOS Sierra+
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

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

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

```
// server.js
const express = require('express');
const Stripe = require('stripe');
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
const app = express();
app.use(express.json());

app.post('/api/create-payment-intent', async (req, res) => {
  const intent = await stripe.paymentIntents.create({
    amount: req.body.amount,
    currency: 'usd',
    automatic_payment_methods: { enabled: true }
  });
  res.json({ client_secret: intent.client_secret });
});

app.listen(3001);
```

**Expected result:** Your backend returns a client_secret that the frontend will use to confirm the payment.

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

```
const stripe = Stripe('pk_test_your_publishable_key');

const paymentRequest = stripe.paymentRequest({
  country: 'US',
  currency: 'usd',
  total: { label: 'Order total', amount: 2000 },
  requestPayerName: true,
  requestPayerEmail: true
});

const elements = stripe.elements();
const prButton = elements.create('paymentRequestButton', {
  paymentRequest
});

paymentRequest.canMakePayment().then(result => {
  if (result) {
    prButton.mount('#payment-request-button');
  } else {
    document.getElementById('payment-request-button').style.display = 'none';
  }
});
```

**Expected result:** The Apple Pay button appears on supported devices. On unsupported devices the button container is hidden.

### 4. Handle the payment token

Listen for the paymentmethod event on the PaymentRequest. Confirm the PaymentIntent with the payment method ID and complete the payment.

```
paymentRequest.on('paymentmethod', async (event) => {
  const res = await fetch('/api/create-payment-intent', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ amount: 2000 })
  });
  const { client_secret } = await res.json();

  const { error, paymentIntent } = await stripe.confirmCardPayment(
    client_secret,
    { payment_method: event.paymentMethod.id },
    { handleActions: false }
  );

  if (error) {
    event.complete('fail');
  } else if (paymentIntent.status === 'requires_action') {
    const { error: confirmError } = await stripe.confirmCardPayment(client_secret);
    if (confirmError) {
      event.complete('fail');
    } else {
      event.complete('success');
    }
  } else {
    event.complete('success');
  }
});
```

**Expected result:** Apple Pay sheet dismisses after successful payment. The PaymentIntent status changes to 'succeeded' in your Stripe Dashboard.

### 5. 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 code example

File: `apple-pay-checkout.js`

```javascript
// apple-pay-checkout.js
// Complete Apple Pay integration with Stripe Payment Request Button

const stripe = Stripe('pk_test_your_publishable_key');

const paymentRequest = stripe.paymentRequest({
  country: 'US',
  currency: 'usd',
  total: {
    label: 'Order total',
    amount: 2000  // $20.00 in cents
  },
  requestPayerName: true,
  requestPayerEmail: true
});

const elements = stripe.elements();
const prButton = elements.create('paymentRequestButton', {
  paymentRequest,
  style: {
    paymentRequestButton: {
      type: 'buy',
      theme: 'dark',
      height: '48px'
    }
  }
});

// Mount button only if Apple Pay / Google Pay is available
paymentRequest.canMakePayment().then(result => {
  if (result) {
    prButton.mount('#payment-request-button');
    if (result.applePay) {
      console.log('Apple Pay is available');
    }
  } else {
    document.getElementById('payment-request-button').style.display = 'none';
    console.log('No wallet payment methods available');
  }
});

// Handle payment
paymentRequest.on('paymentmethod', async (event) => {
  try {
    const res = await fetch('/api/create-payment-intent', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount: 2000 })
    });
    const { client_secret } = await res.json();

    const { error, paymentIntent } = await stripe.confirmCardPayment(
      client_secret,
      { payment_method: event.paymentMethod.id },
      { handleActions: false }
    );

    if (error) {
      event.complete('fail');
      return;
    }

    if (paymentIntent.status === 'requires_action') {
      const { error: actionError } = await stripe.confirmCardPayment(client_secret);
      event.complete(actionError ? 'fail' : 'success');
    } else {
      event.complete('success');
    }
  } catch (err) {
    event.complete('fail');
    console.error('Payment failed:', err);
  }
});
```

## Common mistakes

- **Forgetting to verify the domain in the Stripe Dashboard** — undefined Fix: 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.
- **Testing Apple Pay on a non-Apple device or non-Safari browser** — undefined Fix: Apple Pay only works on Safari and Apple devices. Use Google Pay on Chrome for testing the same Payment Request Button flow.
- **Not calling event.complete() after handling the payment** — undefined Fix: Always call event.complete('success') or event.complete('fail') — otherwise the Apple Pay sheet stays open indefinitely.
- **Serving the page over HTTP instead of HTTPS** — undefined Fix: 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

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

---

Source: https://www.rapidevelopers.com/stripe-guide/how-to-enable-apple-pay-in-stripe
© RapidDev — https://www.rapidevelopers.com/stripe-guide/how-to-enable-apple-pay-in-stripe
