Pay
Digital Wallets
Apple Pay

Apple Pay Integration

Accept payments using cards stored in Apple Wallet


Apple Pay allows customers to make payments using cards they've saved in their Apple Wallet. Instead of manually entering card details, customers can complete checkout by authenticating with Face ID, Touch ID, or their device passcode. This provides a faster, more convenient payment experience while maintaining security through Apple's biometric authentication.

When to Use Apple Pay


Use Apple Pay when you want to provide a fast, streamlined checkout experience for customers using Apple devices. Apple Pay is ideal for mobile-first applications and websites where many customers use Safari on iOS or macOS.

Benefits of Apple Pay

  • Faster Checkout: Customers can complete payment with Face ID, Touch ID, or passcode without typing card numbers
  • Improved Conversion: Reduced friction in checkout leads to higher completion rates
  • Enhanced Security: Apple Pay uses device-specific tokens and biometric authentication
  • Trust and Familiarity: Customers recognize and trust the Apple Pay brand
  • Mobile Optimized: Seamless experience on iPhones, iPads, and Mac computers

Common use cases

  • Mobile Commerce: Optimize checkout for iOS mobile shoppers
  • Subscription Signup: Reduce friction during subscription enrollment
  • Quick Purchases: Enable impulse purchases with one-tap payment
  • Recurring Payments: Save payment methods for subscription billing
  • Multi-Device Experiences: Provide consistent payment across iPhone, iPad, and Mac

Apple Pay Availability


Apple Pay is available in specific environments and requires certain conditions to work properly.

Supported Browsers and Devices

Apple Pay is available on:

  • Safari on iOS 10.1 or later
  • Safari on iPadOS 13.1 or later
  • Safari on macOS 10.12 or later (with Apple Pay-compatible device)

Checking Availability

The Payload.js form provides a callback to detect if Apple Pay is available. Use this with the vanilla form instance (Payload React does not expose this as a prop).

form.applepay(
  (available) => {
    const el = document.getElementById('apple-pay-button')
    if (available) {
      if (el) el.style.display = 'block'
    } else {
      if (el) el.style.display = 'none'
    }
  }
)

Account Activation


Before you can accept Apple Pay payments, you must activate Apple Pay for your Payload account and verify your domains.

Step 1: Register Your Domains

All domains where you'll use Apple Pay must be verified. Each domain requires hosting a domain verification file at a specific location.

Download the Verification File

Download Apple's domain verification file:

https://files.payload.com/applepay/apple-developer-merchantid-domain-association (opens in a new tab)

Host the Verification File

Host the verification file at the following path on each domain:

https://[YOUR_DOMAIN]/.well-known/apple-developer-merchantid-domain-association

For example, if your checkout is at checkout.example.com, host the file at:

https://checkout.example.com/.well-known/apple-developer-merchantid-domain-association

Step 2: Verify Domains in Payload

After hosting the verification file, verify your domains using the Payload Dashboard or API.

Using the Dashboard

  1. Log into your Payload account
  2. Navigate to Settings > Features & Add-ons > Apple Pay
  3. Enter your domain in the verification prompt
  4. Click Verify Domain

Using the API

Alternatively, verify domains programmatically using the API:

curl -X POST https://api.payload.com/applepay_domains \
    -u your_secret_key: \
    -d profile_id=acct_3cKYWcXwONaFxsc5fjGuG \
    -d domain=checkout.example.com

Integrating with Payment Forms


Use Apple Pay with the Payment Form SDK to process payments immediately. This is ideal for checkout flows where customers pay for products or services.

import payload
pl = payload.Session('secret_key_3bW9...', api_version='v2')
 
from flask import Flask, jsonify
 
app = Flask(__name__)
 
@app.route('/payment-form-intent', methods=['POST'])
def create_payment_intent():
    # Create a payment form intent
    intent = pl.Intent.create(
        type='payment_form',
        payment_form={
            'payment_template': {
                'amount': 100.00,
                'description': 'Order #12345',
                'receiver': {
                    'account_id': 'acct_receiver123'
                }
            }
        }
    )
 
    # Send the token to your frontend
    return jsonify({'token': intent.token})
<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
  <style>
    .apple-pay-button {
      -webkit-appearance: -apple-pay-button;
      -apple-pay-button-type: plain;
      -apple-pay-button-style: black;
      width: 100%;
      height: 44px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <form id="payment-form" pl-form="payment">
    <label>Amount</label>
    <input type="number" pl-input="amount" value="100.00" required />
 
    <label>Description</label>
    <input type="text" pl-input="description" value="Purchase" required />
 
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" required />
 
    <label>Billing ZIP Code</label>
    <input type="text" pl-input="billing_address[postal_code]" required />
 
    <div id="apple-pay-button" class="apple-pay-button"></div>
  </form>
 
  <script src="applepay.js"></script>
</body>
</html>
// Fetch client token from your server
fetch('/payment-form-intent', { method: 'POST' })
  .then(res => res.json())
  .then(data => {
    // Initialize Payload with the client token
    Payload(data.token)
 
    // Initialize the payment form
    const form = new Payload.Form(document.getElementById('payment-form'))
 
    // Get the Apple Pay button element
    const button = document.getElementById('apple-pay-button')
 
    // Activate Apple Pay on the button
    form.applepay(button, function(active) {
      if (!active) {
        // Apple Pay is not available on this device
        button.style.display = 'none'
        console.log('Apple Pay is not available')
      }
    })
 
    // Handle successful payment
    form.on('processed', (evt) => {
      console.log('Payment processed:', evt.transaction_id)
      window.location.href = `/payment/success?txn=${evt.transaction_id}`
    })
 
    // Handle declined payment
    form.on('declined', (evt) => {
      console.error('Payment declined:', evt.message)
      alert('Payment declined. Please try a different payment method.')
    })
 
    // Handle errors
    form.on('error', (evt) => {
      console.error('Error:', evt.message)
      alert('Payment failed: ' + evt.message)
    })
  })

This example shows the complete flow for accepting Apple Pay payments:

  1. Backend: Create an intent with type='payment_form' and configure payment amount
  2. Frontend HTML: Add a button with pl-applepay attribute
  3. Frontend JavaScript: Initialize the form and activate Apple Pay with .applepay()
  4. Event Handling: Listen for processed, authorized, or declined events

When the customer clicks the Apple Pay button:

  1. Apple's payment sheet opens with available cards from Apple Wallet
  2. Customer authenticates with Face ID, Touch ID, or passcode
  3. Payment is processed immediately
  4. The processed event fires with the transaction ID

Integrating with Payment Method Forms


Use Apple Pay with the Payment Method Form SDK to save payment methods for future use. This is ideal for subscription signups, wallet management, and recurring billing setup.

import payload
from flask import Flask, jsonify
 
pl = payload.Session('secret_key_3bW9...', api_version='v2')
 
app = Flask(__name__)
 
 
@app.route('/create-payment-method-intent', methods=['POST'])
def create_intent():
    # Create an intent for a payment method form
    intent = pl.Intent.create(
        type="payment_method_form",
        payment_method_form={
            "payment_method_template": {
                "account_id": "acct_customer123",
                # Optionally configure defaults
                'transfer_type': 'two_way',
            }
        },
    )
 
    # Return the client token to the frontend
    return jsonify({'client_token': intent.token})
 
 
 
if __name__ == "__main__":
    app.run(port=3000)
<!DOCTYPE html>
<html>
<head>
  <script src="https://payload.com/Payload.js"></script>
  <style>
    .apple-pay-button {
      -webkit-appearance: -apple-pay-button;
      -apple-pay-button-type: plain;
      -apple-pay-button-style: black;
      width: 100%;
      height: 44px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <form id="payment-method-form" pl-form="payment_method">
    <label>Account Holder Name</label>
    <input type="text" pl-input="account_holder" required />
 
    <label>Billing ZIP Code</label>
    <input type="text" pl-input="billing_address[postal_code]" required />
 
    <div id="apple-pay-button" class="apple-pay-button"></div>
  </form>
 
  <script src="applepay.js"></script>
</body>
</html>
// Fetch client token from your server
fetch('/payment-method-form-intent', { method: 'POST' })
  .then(res => res.json())
  .then(data => {
    // Initialize Payload with the client token
    Payload(data.token)
 
    // Initialize the payment method form
    const form = new Payload.Form(document.getElementById('payment-method-form'))
 
    // Get the Apple Pay button element
    const button = document.getElementById('apple-pay-button')
 
    // Activate Apple Pay on the button
    form.applepay(button, function(active) {
      if (!active) {
        // Apple Pay is not available on this device
        button.style.display = 'none'
        console.log('Apple Pay is not available')
      }
    })
 
    // Handle successful payment method creation
    form.on('success', (evt) => {
      console.log('Payment method created:', evt.payment_method_id)
      window.location.href = '/account/payment-methods?success=true'
    })
 
    // Handle errors
    form.on('error', (evt) => {
      console.error('Error:', evt.message)
      alert('Failed to save payment method: ' + evt.message)
    })
  })

This example shows the complete flow for saving Apple Pay payment methods:

  1. Backend: Create an intent with type='payment_method_form'
  2. Frontend HTML: Add a button with pl-applepay attribute
  3. Frontend JavaScript: Initialize the form and activate Apple Pay with .applepay()
  4. Event Handling: Listen for success or error events

When the customer clicks the Apple Pay button:

  1. Apple's payment sheet opens with available cards
  2. Customer authenticates and selects a card
  3. Payment method is saved without processing a payment
  4. The success event fires with the payment method ID

Setting Account Defaults

Configure the saved payment method as the default for automatic billing:

# On your backend
intent = pl.Intent.create(
    type="payment_method_form",
    payment_method_form={
        "payment_method_template": {
            "account_id": "acct_abc123",
            "account_defaults": {
                "paying": "payments"  # Make this the default payment method
            }
        }
    }
)

Styling the Apple Pay Button


You can customize the Apple Pay button appearance using CSS or by providing custom button markup.

Using Apple Pay Button Styles

Apple provides standard button styles that match iOS design guidelines:

<button pl-applepay class="apple-pay-button apple-pay-button-black">
  <!-- Apple Pay button content is rendered automatically -->
</button>
.apple-pay-button {
  -webkit-appearance: -apple-pay-button;
  -apple-pay-button-type: plain; /* plain, buy, donate, check-out, book, subscribe */
  -apple-pay-button-style: black; /* black, white, white-outline */
}
 
.apple-pay-button-black {
  -apple-pay-button-style: black;
}

Custom Button Styling

Alternatively, create a custom button that matches your design:

<button pl-applepay class="custom-apple-pay">
  <img src="/apple-pay-logo.svg" alt="Apple Pay" />
  <span>Pay with Apple Pay</span>
</button>
.custom-apple-pay {
  background-color: #000;
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 12px 24px;
  font-size: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
 
.custom-apple-pay:hover {
  background-color: #333;
}

Handling Events


The Payment Form SDK emits events specific to Apple Pay interactions and payment processing.

Success Events

form.on('success', (evt) => {
  console.log('Payment processed:', evt.transaction_id)
  window.location.href = `/success?txn=${evt.transaction_id}`
})

Error Events

form.on('declined', (evt) => {
  console.error('Payment declined:', evt.message)
  alert('Your payment was declined. Please try another card.')
})
 
form.on('error', (evt) => {
  console.error('Apple Pay error:', evt.message)
  alert(`Error: ${evt.message}`)
})

Best Practices


Follow these best practices for optimal Apple Pay integration.

User Experience

  • Show Apple Pay prominently on checkout pages for Safari users
  • Hide the button on unsupported browsers/devices using the availability callback
  • Provide alternatives like manual card entry for users without Apple Pay
  • Use standard styling that matches Apple's design guidelines
  • Add loading states during payment processing

Security

  • Always use HTTPS - Apple Pay requires secure connections
  • Validate on backend - Don't rely solely on frontend validation
  • Keep domains verified - Regularly check domain verification status

Testing

  • Test on real devices - Always test on actual iOS devices before launch
  • Test all card networks - Verify Visa, Mastercard, Amex, and Discover work correctly
  • Test error scenarios - Ensure declined payments are handled gracefully
  • Test cancellation - Verify the experience when users cancel the Apple Pay sheet

Next Steps

Enhance your payment experience with additional features and payment options


Manage Payments and Subscriptions

Use Payment Processing to understand the payment lifecycle and status tracking, monitor Transaction Status to check payment states, set up Recurring Payments for automatic billing with saved methods, and explore Autopay Overview to learn how Autopay enrollment works.

Add More Payment Options

Accept Google Pay payments from Google Pay users, enable instant bank account payments with Plaid, and build custom forms with Payment Form for manual card and bank account payments.

Monitor and Analyze Payments

Use Webhook Events to monitor payment events in real-time, track payment metrics with Reporting Overview, and analyze payment data with Transaction Reports.


Related articles