Integrating Apple Pay in Safari with the ApplePay JS API
Learn how to add Apple Pay to a Safari‑only checkout using the ApplePaySession API, with a minimal code example and notes on domain verification and fallback handling.
03 Dec 2025, 05:55 UTC

Problem: frictionless checkout on Apple devices
When a shopper uses an iPhone or Mac, they expect to complete a purchase with a single tap or click, without entering card details each time. If a website only offers generic card forms, the checkout flow feels slower and can increase abandonment, especially on mobile where typing is cumbersome.
How Apple Pay JS works in Safari
Safari exposes a web‑only API called Apple Pay JS that lets a merchant create a payment sheet directly in the browser. The API is available starting with Safari 13 on macOS 10.15+ and iOS 13+. It requires three things:
- A valid Apple Pay merchant ID issued through the Apple Developer portal.
- Domain verification proving that you control the web origin where the payment sheet will appear.
- A secure HTTPS context (TLS 1.2 or higher).
The core object is ApplePaySession. You first check if the user can make payments with ApplePay.canMakePayments(). If true, you create a session, listen for callbacks, and finally complete the transaction after your server validates the payment token.
Minimal implementation example
Place this script on a page served over HTTPS. Replace the placeholders with your own values.
// 1. Check availability
if (!window.ApplePaySession) {
console.warn('Apple Pay JS not available in this browser');
// Show fallback payment UI
} else if (!ApplePaySession.canMakePayments()) {
console.warn('User cannot make Apple Pay payments');
} else {
// 2. Create the session
const request = {
countryCode: 'US',
currencyCode: 'USD',
supportedNetworks: ['visa', 'masterCard', 'amex'],
merchantCapabilities: ['supports3DS'],
total: { label: 'My Store', amount: '42.00' } // example amount
};
const session = new ApplePaySession(3, request);
// 3. Validate the merchant with your server
session.onvalidatemerchant = async (event) => {
const validationURL = event.validationURL;
const merchantSession = await fetch('/apple-pay/validate-merchant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ validationURL, merchantId: 'YOUR_MERCHANT_ID' })
}).then(r => r.json());
session.completeMerchantValidation(merchantSession);
};
// 4. Authorize the payment
session.onpaymentauthorized = async (event) => {
const token = event.payment.token; // encrypted payment data
// Send token to your backend for processing
const result = await fetch('/apple-pay/process-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token })
}).then(r => r.json());
if (result.status === 'success') {
session.completePayment(ApplePaySession.STATUS_SUCCESS);
} else {
session.completePayment(ApplePaySession.STATUS_FAILURE);
}
};
// 5. Begin the payment sheet
session.begin();
}
Where to run: the script executes in the page’s JavaScript context, so it must be loaded in Safari on a supported device. Required permissions: the page must be served via HTTPS with a valid certificate; no special user permissions beyond granting the payment sheet when it appears.
Trade‑offs and limitations
- Device coverage: Apple Pay JS works only on Apple hardware (iPhone, iPad, Mac) running the minimum Safari versions. Users on Android or Windows will not see the Apple Pay button.
- Domain verification: You must register each exact origin (including subdomains) in the Apple Pay merchant dashboard. A mismatch causes the
onvalidatemerchantcallback to fail. - No automatic fallback: The API does not try other payment methods if Apple Pay is unavailable; you must provide your own alternative checkout UI.
- Server‑side dependency: Your backend must implement the Apple Pay payment processing endpoints (merchant validation and token decryption) or use a provider that does.
What to do next
Start by confirming API availability in your target Safari version:
console.log(ApplePaySession ? 'ApplePaySession present' : 'ApplePaySession missing');
console.log(ApplePaySession.canMakePayments() ? 'Can make payments' : 'Cannot make payments');
If both logs show true, proceed with domain verification in the Apple Developer portal and implement the merchant‑validation and payment‑processing endpoints on your server. After that, integrate the snippet above, test end‑to‑end on a real device, and monitor for any validation errors in the console.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.