Learn how to use the Apple Pay component for Web in your project.
Every component follows the same basic three-step lifecycle:
- Create the component and optionally add your own configuration.
- Mount the component. This is what makes the component visible and interactive.
- Unmount the component. This is a clean-up step that clears up resources.
To use the Apple Pay component, you first need to:
- Install Components for Web.
- Complete the Apple Pay onboarding process in the Unity Portal.
- Ensure your website is served over HTTPS (required for Apple Pay).
- Verify your domain with Apple Pay (configured in Unity Portal).
Apple Pay for Web has specific requirements for optimal functionality.
- Safari 11.1+ on macOS 10.13.4+.
- Safari on iOS 11.2+.
- Other WebKit-based browsers with Apple Pay support.
- iOS devices: iPhone 6 or later, iPad Pro, iPad (5th generation) or later, iPad Air 2, iPad mini 3 or later.
- macOS devices: MacBook Pro with Touch Bar, MacBook Air (2018 or later), iMac Pro, Mac Pro (2019 or later), or any Mac with Touch ID.
- The customer must have a supported payment method in their Wallet.
- The device must have Touch ID, Face ID, or passcode enabled.
To get started, initialise the Checkout SDK with Apple Pay support.
import { PxpCheckout } from 'pxp-checkout-sdk';
const pxpSdk = PxpCheckout.initialize({
environment: 'test', // or 'live' for production
session: {
sessionId: 'your-session-id',
allowedFundingTypes: {
wallets: {
applePay: {
merchantId: 'merchant.com.yourcompany.yourapp'
}
}
}
},
ownerId: 'your-owner-id',
ownerType: 'Merchant',
transactionData: {
currency: 'USD',
amount: 25.00,
merchantTransactionId: 'txn-' + Date.now(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: 'Purchase'
}
},
onGetShopper: () => {
// Return current shopper data dynamically
return Promise.resolve({
id: 'shopper-' + Date.now(),
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
});
}
});| Property | Description |
|---|---|
environmentstring required | The environment type. Possible values:
|
sessionsessionData required | Details about the checkout session. |
session.sessionIdstring required | The unique session identifier. |
session.allowedFundingTypes.wallets.applePay.merchantIdstring required | Your Apple Pay merchant identifier. |
ownerIdstring required | The identifier of the owner related to the ownerType. |
ownerTypestring required | The type of owner. Possible values:
|
onGetShopperfunction | Callback function to provide shopper data dynamically. Returns a Promise with shopper information including ID, email, name, and contact details. |
transactionDataobject required | Details about the transaction. |
transactionData.currencystring (3 characters) required | The currency code associated with the transaction, in ISO 4217 format. |
transactionData.amountnumber required | The transaction amount. |
transactionData.entryTypestring required | The entry type. Possible values:
|
transactionData.intentstring required | The transaction intent. Possible values:
|
transactionData.merchantTransactionIdstring required | A unique identifier for this transaction. |
transactionData.merchantTransactionDatefunction required | A function that returns the date and time of the transaction, in ISO 8601 format. |
Next, you're going to create the Apple Pay component configuration.
const config = {
merchantDisplayName: 'Your Store',
paymentDescription: 'Purchase from Your Store',
usingCss: false, // Use official Apple Pay SDK (recommended)
style: {
type: 'buy',
buttonstyle: 'black',
height: '44px',
borderRadius: '4px'
},
paymentRequest: {
countryCode: 'US',
currencyCode: 'USD',
merchantCapabilities: ['supports3DS', 'supportsEMV'],
supportedNetworks: ['visa', 'masterCard', 'amex'],
total: {
label: 'Total',
amount: '25.00'
}
},
onError: (error) => console.error('Apple Pay Error:', error),
onPostAuthorisation: async (data) => {
const result = await getAuthorisationResultFromGateway(
data.merchantTransactionId,
data.systemTransactionId
);
if (result.status === 'Authorised') {
console.log('Payment successful!');
// Handle successful payment
}
}
};| Parameter | Description |
|---|---|
merchantDisplayNamestring (≤ 64 characters) required | The name of your store as it appears to customers during payment. |
paymentDescriptionstring (≤ 128 characters) required | A description of the payment that appears to customers. |
usingCssboolean | Whether to use custom CSS rendering instead of the official Apple Pay SDK. Defaults to false. |
styleobject | Button styling configuration. |
style.typestring required | The button type. Possible values:
|
style.buttonstylestring required | The button style. Possible values:
|
style.heightstring | The button height (e.g., '44px', '50px'). |
style.borderRadiusstring | The button border radius (e.g., '4px', '8px'). |
paymentRequestobject required | Apple Pay payment request configuration. |
paymentRequest.countryCodestring (2 characters) required | The country code, in ISO 3166-1 alpha-2 format. |
paymentRequest.currencyCodestring (3 characters) required | The currency code, in ISO 4217 format. |
paymentRequest.merchantCapabilitiesarray of strings required | Payment processing capabilities. Possible values:
|
paymentRequest.supportedNetworksarray of strings required | Supported card networks. Possible values:
|
paymentRequest.totalobject required | The total payment amount. |
paymentRequest.total.labelstring required | A short description of the total. |
paymentRequest.total.amountstring required | The total amount as a string with decimal precision. |
paymentRequest.total.typestring | The total type. Possible values:
|
paymentRequest.requiredBillingContactFieldsarray of strings | The required billing contact fields. Possible values:
|
paymentRequest.requiredShippingContactFieldsarray of strings | The required shipping contact fields. Possible values:
|
paymentRequest.shippingMethodsarray of objects | The available shipping methods. |
paymentRequest.shippingMethods.identifierstring required | Unique identifier for the shipping method. |
paymentRequest.shippingMethods.labelstring required | The display name for the shipping method. |
paymentRequest.shippingMethods.detailstring | Additional details about the shipping method. |
paymentRequest.shippingMethods.amountstring required | The shipping cost as a string. |
paymentRequest.lineItemsarray of objects | Individual line items for the payment. |
paymentRequest.lineItems.labelstring required | The display name for the line item. |
paymentRequest.lineItems.amountstring required | The line item amount as a string. |
paymentRequest.lineItems.typestring | The line item type. Possible values:
|
Create an HTML container where the Apple Pay button will be mounted.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apple Pay Checkout</title>
</head>
<body>
<div class="checkout-container">
<h2>Complete your purchase</h2>
<div class="payment-summary">
<div class="item">
<span>Product</span>
<span>$20.00</span>
</div>
<div class="item">
<span>Tax</span>
<span>$3.00</span>
</div>
<div class="item">
<span>Shipping</span>
<span>$2.00</span>
</div>
<hr>
<div class="total">
<span>Total</span>
<span>$25.00</span>
</div>
</div>
<!-- Apple Pay button container -->
<div id="apple-pay-container" style="margin: 20px 0;"></div>
<div class="alternative-payments">
<p>Or pay with card</p>
<!-- Other payment methods -->
</div>
</div>
</body>
</html>For the component to be visible and functional, you need to mount it. Make sure to supply both the component configuration and the container ID.
const applePayComponent = pxpSdk.create('apple-pay-button', config);
applePayComponent.mount('apple-pay-container');At this point, your Apple Pay button is ready to use and will appear in the specified container.
The component will automatically handle the payment flow. You can listen for payment results through the callback functions:
const config = {
// ... other configuration
onPreAuthorisation: async () => {
// Called before payment authorisation
// Return transaction initialisation data
console.log('Pre-authorisation started');
return {
addressVerification: true,
riskScreeningData: {
// Kount risk screening data
}
};
},
onPostAuthorisation: async (data) => {
console.log('Payment completed');
console.log('Merchant Transaction ID:', data.merchantTransactionId);
console.log('System Transaction ID:', data.systemTransactionId);
// Retrieve authorization result from backend
const result = await getAuthorisationResultFromGateway(
data.merchantTransactionId,
data.systemTransactionId
);
if (result.status === 'Authorised') {
// Payment was successful
console.log('Payment authorised successfully');
console.log('Transaction ID:', result.transactionId);
// Redirect to success page or show success message
window.location.href = '/payment-success';
} else {
// Payment was declined or error occurred
console.log('Payment failed:', result.errorReason);
// Show error message to user
}
},
onError: (error) => {
console.error('Apple Pay error:', error);
// Handle and display error to user
},
onCancel: (error) => {
console.log('Payment cancelled by user');
// Handle cancellation
}
};Lastly, remember to unmount the component when it's no longer needed to free up resources.
applePayComponent.unmount();You can configure the appearance and behaviour of the Apple Pay component to fit your brand. We've documented all configurable parameters in the Customisation page.
const customConfig = {
// ... other configuration
usingCss: true, // Enable custom CSS
style: {
type: 'buy',
buttonstyle: 'black',
template: '<button class="custom-apple-pay-btn">Pay with Apple Pay</button>',
templateCSS: `
.custom-apple-pay-btn {
background: linear-gradient(135deg, #000 0%, #333 100%);
color: white;
border: none;
border-radius: 8px;
height: 50px;
width: 100%;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.custom-apple-pay-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
`
}
};The Apple Pay component emits events based on user interaction, shipping changes, and payment method updates. You can implement callback functions to handle these events and perform actions such as updating totals or validating addresses. For more information about all the available events, see the Events page.
const eventConfig = {
// ... other configuration
onShippingContactSelected: async (contact) => {
// Update totals based on shipping address
const shipping = calculateShipping(contact.postalAddress);
return {
newShippingMethods: [
{
identifier: 'standard',
label: 'Standard Shipping',
amount: shipping.standard.toString(),
detail: '5-7 business days'
}
],
newTotal: {
label: 'Total',
amount: (25.00 + shipping.standard).toString()
}
};
},
onPaymentMethodSelected: async (paymentMethod) => {
// Handle payment method changes
console.log('Selected payment method:', paymentMethod);
return {
newTotal: {
label: 'Total',
amount: '25.00'
}
};
}
};Error handling is crucial for payment components because they deal with sensitive financial data and complex validation rules. Errors can happen due to issues with configuration, validation, authentication, or connectivity. For more details about error handling, see the Data Validation page.
const errorConfig = {
// ... other configuration
onError: (error) => {
if (error instanceof ApplePayValidationException) {
// Handle validation errors
console.error('Validation error:', error.message);
showUserError('Please check your payment information and try again.');
} else if (error instanceof ApplePayHttpRequestFailedException) {
// Handle network errors
console.error('Network error:', error.message);
showUserError('Connection error. Please check your internet and try again.');
} else {
// Handle other errors
console.error('Unexpected error:', error);
showUserError('An unexpected error occurred. Please try again.');
}
}
};
function showUserError(message) {
const errorDiv = document.getElementById('error-message');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apple Pay Checkout Example</title>
<style>
.checkout-container {
max-width: 400px;
margin: 50px auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
.payment-summary {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.item, .total {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.total {
font-weight: 600;
font-size: 18px;
}
hr {
border: none;
border-top: 1px solid #ddd;
margin: 15px 0;
}
#apple-pay-container {
margin: 20px 0;
}
.error-message {
background: #ffebee;
color: #c62828;
padding: 12px;
border-radius: 4px;
margin: 10px 0;
display: none;
}
.success-message {
background: #e8f5e8;
color: #2e7d32;
padding: 12px;
border-radius: 4px;
margin: 10px 0;
display: none;
}
</style>
</head>
<body>
<div class="checkout-container">
<h2>Complete your purchase</h2>
<div class="payment-summary">
<div class="item">
<span>Premium T-Shirt</span>
<span>$20.00</span>
</div>
<div class="item">
<span>Sales Tax</span>
<span>$3.00</span>
</div>
<div class="item">
<span>Shipping</span>
<span>$2.00</span>
</div>
<hr>
<div class="total">
<span>Total</span>
<span>$25.00</span>
</div>
</div>
<div id="error-message" class="error-message"></div>
<div id="success-message" class="success-message"></div>
<!-- Apple Pay button will be mounted here -->
<div id="apple-pay-container"></div>
<div class="alternative-payments">
<p style="text-align: center; color: #666; margin: 20px 0;">
Or pay with credit card
</p>
<!-- Other payment method buttons would go here -->
</div>
</div>
<script type="module">
import { PxpCheckout, AuthorisedSubmitResult, DeclinedSubmitResult, ExceptionSubmitResult } from 'pxp-checkout-sdk';
// Initialise the SDK
const pxpSdk = PxpCheckout.initialize({
environment: 'test',
session: {
sessionId: 'your-session-id-from-backend',
allowedFundingTypes: {
wallets: {
applePay: {
merchantId: 'merchant.com.yourcompany.yourapp'
}
}
}
},
ownerId: 'your-owner-id',
ownerType: 'Merchant',
transactionData: {
currency: 'USD',
amount: 25.00,
merchantTransactionId: 'txn-' + Date.now(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: 'Purchase'
}
},
onGetShopper: () => {
return Promise.resolve({
id: 'shopper-' + Date.now(),
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
});
},
onGetShippingAddress: () => {
return Promise.resolve({
address: '123 Main Street',
city: 'San Francisco',
state: 'CA',
postalCode: '94103',
countryCode: 'US'
});
}
});
// Apple Pay component configuration
const config = {
merchantDisplayName: 'Your Store Name',
paymentDescription: 'Premium T-Shirt Purchase',
usingCss: false, // Use official Apple Pay SDK
style: {
type: 'buy',
buttonstyle: 'black',
height: '50px',
borderRadius: '8px'
},
paymentRequest: {
countryCode: 'US',
currencyCode: 'USD',
merchantCapabilities: ['supports3DS', 'supportsEMV'],
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
total: {
label: 'Your Store Name',
amount: '25.00',
type: 'final'
},
lineItems: [
{
label: 'Premium T-Shirt',
amount: '20.00'
},
{
label: 'Sales Tax',
amount: '3.00'
},
{
label: 'Shipping',
amount: '2.00'
}
],
requiredBillingContactFields: ['postalAddress', 'name', 'email'],
requiredShippingContactFields: ['postalAddress', 'name', 'phone'],
shippingMethods: [
{
identifier: 'standard',
label: 'Standard Shipping',
detail: '5-7 business days',
amount: '2.00'
},
{
identifier: 'express',
label: 'Express Shipping',
detail: '2-3 business days',
amount: '5.00'
}
]
},
// Event handlers
onPreAuthorisation: async () => {
console.log('Pre-authorisation started');
showMessage('Processing payment...', 'info');
return {
addressVerification: true,
riskScreeningData: {
// Kount integration data would go here
}
};
},
onPostAuthorisation: async (data) => {
console.log('Payment completed');
console.log('Merchant Transaction ID:', data.merchantTransactionId);
// Retrieve authorization result from backend
const result = await getAuthorisationResultFromGateway(
data.merchantTransactionId,
data.systemTransactionId
);
if (result.status === 'Authorised') {
showMessage('Payment successful! Redirecting...', 'success');
console.log('Transaction ID:', result.transactionId);
// Redirect to success page after a short delay
setTimeout(() => {
window.location.href = '/payment-success?txn=' + data.merchantTransactionId;
}, 2000);
} else {
showMessage('Payment failed: ' + (result.errorReason || 'Please try again'), 'error');
}
},
onShippingContactSelected: async (contact) => {
console.log('Shipping contact selected:', contact);
// Calculate shipping based on address
const shippingCost = calculateShippingCost(contact.postalAddress);
const tax = calculateTax(contact.postalAddress);
const newTotal = 20.00 + shippingCost + tax;
return {
newShippingMethods: [
{
identifier: 'standard',
label: 'Standard Shipping',
detail: '5-7 business days',
amount: shippingCost.toString()
}
],
newTotal: {
label: 'Your Store Name',
amount: newTotal.toFixed(2)
},
newLineItems: [
{
label: 'Premium T-Shirt',
amount: '20.00'
},
{
label: 'Sales Tax',
amount: tax.toFixed(2)
},
{
label: 'Shipping',
amount: shippingCost.toFixed(2)
}
]
};
},
onShippingMethodSelected: async (method) => {
console.log('Shipping method selected:', method);
const baseAmount = 20.00;
const tax = 3.00;
const shippingCost = parseFloat(method.amount);
const newTotal = baseAmount + tax + shippingCost;
return {
newTotal: {
label: 'Your Store Name',
amount: newTotal.toFixed(2)
},
newLineItems: [
{
label: 'Premium T-Shirt',
amount: '20.00'
},
{
label: 'Sales Tax',
amount: '3.00'
},
{
label: 'Shipping',
amount: method.amount
}
]
};
},
onError: (error) => {
console.error('Apple Pay error:', error);
showMessage('Payment error: ' + error.message, 'error');
},
onCancel: (error) => {
console.log('Payment cancelled by user');
showMessage('Payment was cancelled', 'info');
}
};
// Helper functions
function showMessage(message, type) {
const errorDiv = document.getElementById('error-message');
const successDiv = document.getElementById('success-message');
// Hide all messages first
errorDiv.style.display = 'none';
successDiv.style.display = 'none';
if (type === 'error') {
errorDiv.textContent = message;
errorDiv.style.display = 'block';
} else if (type === 'success') {
successDiv.textContent = message;
successDiv.style.display = 'block';
} else {
// For info messages, use success styling but different color
successDiv.textContent = message;
successDiv.style.display = 'block';
successDiv.style.background = '#e3f2fd';
successDiv.style.color = '#1565c0';
}
}
function calculateShippingCost(address) {
// Simple shipping calculation based on state/country
if (address.countryCode === 'US') {
return address.administrativeArea === 'CA' ? 5.00 : 2.00;
}
return 10.00; // International shipping
}
function calculateTax(address) {
// Simple tax calculation
const taxRates = {
'CA': 0.0875, // California
'NY': 0.08, // New York
'TX': 0.0625 // Texas
};
const rate = taxRates[address.administrativeArea] || 0.06;
return 20.00 * rate;
}
// Create and mount the Apple Pay component
try {
const applePayComponent = pxpSdk.create('apple-pay-button', config);
applePayComponent.mount('apple-pay-container');
console.log('Apple Pay component mounted successfully');
} catch (error) {
console.error('Failed to initialise Apple Pay:', error);
showMessage('Apple Pay is not available on this device/browser', 'error');
}
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
if (window.applePayComponent) {
window.applePayComponent.unmount();
}
});
</script>
</body>
</html>