Apple Pay

Accept Apple Pay for fast, secure checkout on Safari and iOS devices.
View as Markdown

Apple Pay lets customers pay using cards saved to their Apple Wallet with a single tap or glance.

Prerequisites

PaymentKit.js prepares Apple Pay automatically when it initializes — the recommended flow has no manual prepare step. You reveal your button once the SDK reports Apple Pay is ready (see Show the express button), and the customer’s tap submits the payment directly.

Auto-prepare only succeeds when the checkout session’s account has an express-checkout processor configured with Apple Pay enabled. If none is configured, the SDK stays in the not-ready state and your onApplePayReady callback reports false — so your button simply never appears.

Add the browser script for your processor:

Add Stripe.js to your page:

1<script src="https://js.stripe.com/v3/"></script>

Airwallex processors must also have Apple Pay activated in your Airwallex dashboard. Enabling Apple Pay in your PaymentKit dashboard alone is not enough — Apple Pay must be enabled as a payment method on your Airwallex account (including any required domain registration) before it can be tested or charged. If it isn’t activated on the Airwallex side, the Apple Pay sheet will fail to complete even when your PaymentKit configuration is correct.

Setup

1<script src="https://unpkg.com/@payment-kit-js/vanilla/dist/cdn/paymentkit.min.js"></script>
2<script>
3 const paymentKit = PaymentKit.default({
4 environment: 'production',
5 secureToken: 'your_secure_token',
6 paymentMethods: [PaymentKit.PaymentMethods.applePay]
7 });
8</script>

Show the express button

The SDK prepares Apple Pay automatically as soon as it initializes — you no longer need to call prepareApplePay yourself. Use onApplePayReady to show or hide your express button based on whether Apple Pay is available, and notifyAmountChanged to re-prepare whenever the amount changes.

React to readiness

Register a callback with onApplePayReady. It fires immediately with the current state, then again on every change (for example when a re-prepare starts or finishes). Register as many callbacks as you need — none are overwritten.

1paymentKit.apple_pay.onApplePayReady((isReady) => {
2 applePayButton.hidden = !isReady;
3});

While the SDK is re-preparing (see below), it reports isReady: false, then true again once the new session is ready — so the same callback naturally disables the button during the gap.

Re-prepare after the amount changes

Apple Pay sessions are pinned to a specific amount. Whenever the cart total changes — a coupon is applied, quantity is updated, shipping is added — call notifyAmountChanged() so the SDK clears the stale session and prepares a fresh one. It returns a promise that resolves once the new session is ready.

1await paymentKit.apple_pay.notifyAmountChanged();

Your onApplePayReady callback fires across the re-prepare (false while in flight, then true), so the button hides and reappears on its own. Calling it again while a prepare is already running coalesces the calls — the promise resolves once the latest prepare completes.

onApplePayReady and notifyAmountChanged are methods on paymentKit.apple_pay. They are the recommended way to drive the express button — the manual prepareApplePay flow below is retained for backward compatibility.

Prepare Apple Pay (legacy)

prepareApplePay is deprecated. The SDK now prepares automatically on init — observe readiness with onApplePayReady and re-prepare with notifyAmountChanged instead (see above). This section documents the older manual flow.

If you opt into the legacy manual flow, call prepareApplePay before showing the Apple Pay button to check availability and pre-initialize the session — this must happen before the user clicks. With auto-prepare (the recommended flow above), you don’t call this at all.

1import { prepareApplePay, isApplePayPrepared, clearPreparedApplePay } from '@payment-kit-js/vanilla/payment-methods/apple-pay';
2
3const result = await prepareApplePay(
4 'https://app.paymentkit.com', // API base URL
5 'your_secure_token',
6 {
7 processorId: 'proc_abc123',
8 processorType: 'airwallex', // Required for Airwallex processors
9 customerInfo: {
10 first_name: 'Jane',
11 last_name: 'Smith'
12 },
13 country: 'US'
14 },
15 'production' // environment
16);
17
18if (result.success) {
19 // Show Apple Pay button
20}

Airwallex processors: You must pass processorType: 'airwallex' in both prepareApplePay and submit options. Without this, the SDK will route the payment through the Stripe flow instead of Airwallex, causing a backend error. Stripe processors work without processorType.

Submit payment

Attach submit to the same button you reveal with onApplePayReady. In the auto-prepare flow the SDK fills processorId, processorType, and country from the prepared session, and the Apple Pay sheet supplies the final payer details — so you don’t pass them.

1applePayButton.addEventListener('click', () => {
2 paymentKit.submit({
3 fields: {},
4 paymentMethod: 'apple_pay',
5 options: {
6 customerInfo: {
7 first_name: 'Jane',
8 last_name: 'Smith'
9 }
10 },
11 onSuccess: (result) => {
12 console.log('Transaction ID:', result.transaction_id);
13 console.log('Checkout Session:', result.checkout_session_id);
14 window.location.href = '/success';
15 },
16 onError: (errors) => {
17 if (errors.apple_pay) {
18 // Surface the error or fall back to the card form
19 }
20 }
21 });
22});

If you use the legacy manual flow, pass processorId, processorType ("airwallex" for Airwallex), and country in options to match what you passed to prepareApplePay.

Cleanup

In the auto-prepare flow the SDK manages prepared state per instance, so no manual cleanup call is required. If you use the legacy prepareApplePay flow, clear the prepared state when unmounting or navigating away:

1clearPreparedApplePay();

Options

Submit options

In the auto-prepare flow, processorId, processorType, and country are filled from the prepared session — you only pass them if you use the legacy manual flow.

OptionTypeDescription
processorIdstringYour processor ID with Apple Pay enabled. Auto-filled from the prepared session; required only for the legacy flow.
processorType"stripe" | "airwallex"Auto-filled from the session. For the legacy flow, set to "airwallex" for Airwallex processors.
customerInfo.first_namestringCustomer’s first name. The Apple Pay sheet supplies the final payer name.
customerInfo.last_namestringCustomer’s last name.
countrystringTwo-letter country code (e.g., "US"). Auto-filled from the session in the express flow.
amountnumberAmount in atomic units (cents) for the Apple Pay sheet display
currencystringCurrency code (e.g., "usd")
merchantNamestringMerchant display name shown on the Apple Pay sheet
mockScenarioApplePayMockScenarioTesting only. Use "success" or "cancelled"

prepareApplePay options (legacy)

These apply only to the deprecated manual prepareApplePay flow.

OptionTypeDescription
processorIdstringRequired. Your processor ID with Apple Pay enabled
processorType"stripe" | "airwallex"Required for Airwallex. Set to "airwallex" when using an Airwallex processor
customerInfo.first_namestringRequired. Customer’s first name
customerInfo.last_namestringRequired. Customer’s last name
countrystringRequired. Two-letter country code (e.g., "US")
amountnumberAmount in atomic units (cents) for the Apple Pay sheet display
currencystringCurrency code (e.g., "usd")
merchantNamestringMerchant display name shown on the Apple Pay sheet
mockScenarioApplePayMockScenarioTesting only. Use "success" or "cancelled" to simulate Apple Pay flows without a real device

Browser support

Apple Pay works on:

  • Safari on macOS (with Touch ID or a paired iPhone/Apple Watch)
  • Safari on iOS and iPadOS (with Face ID, Touch ID, or passcode)

Apple Pay requires Safari. For Stripe processors, PaymentKit.js uses Stripe’s Payment Request API, which also only surfaces Apple Pay in Safari. For Airwallex processors, the native ApplePaySession API is used directly, which is Safari-only. Always provide card payments as a fallback.

Error handling

In the auto-prepare flow, availability problems surface through onApplePayReady(false) — the button never appears — rather than as submit errors. Processor ID is required means the checkout session has no express-checkout processor configured.

ErrorCause
Processor ID is requiredNo processor available — the session has no express-checkout processor configured (or none passed in the legacy flow)
Apple Pay not available on this device (requires Safari)Airwallex: device or browser does not support Apple Pay (non-Safari)
Apple Pay not available on this deviceAirwallex: canMakePayment() returned false — no cards in wallet or hardware restriction
Apple Pay is not available on this device or Stripe accountStripe: prepareApplePay could not confirm Apple Pay availability via Payment Request API
Stripe.js not loaded. Add <script src="https://js.stripe.com/v3/"></script> to your page.Stripe.js script not present when initializing the Stripe adapter
Apple Pay cancelled by userCustomer dismissed the Apple Pay sheet
Failed to start Apple PayAPI call to the /apple-pay/start endpoint failed
Apple Pay failedAirwallex payment sheet returned a non-cancelled failure
3DS authentication failedAirwallex 3DS challenge completed without success
Too many authentication attempts. Please try again.Airwallex 3DS loop exceeded the maximum retry limit
Payment failedConfirm or verify endpoint returned a non-success charge status
Apple Pay error: {message}Unexpected exception during the payment flow