Process standard one-time Apple Pay transactions for Web with automatic 3D Secure authentication.
The SDK automatically handles 3D Secure (3DS) authentication based on transaction risk, regulatory requirements, and issuer policies.
By implementing Apple Pay for standard payments, you benefit from:
- Automatic 3DS evaluation: The SDK determines when 3DS authentication is required based on risk assessment, transaction amount, and regulatory requirements.
- Enhanced security: 3DS adds multiple layers of authentication on top of Apple Pay's built-in biometric security.
- Liability shift: Successful 3DS authentication typically shifts fraud liability from merchant to card issuer.
- Seamless experience: 3DS often runs in the background with Apple Pay, providing frictionless authentication without additional customer steps.
- Higher approval rates: Banks are more likely to approve transactions with 3DS authentication.
- Fast checkout: For low-risk transactions, payments process immediately without 3DS overhead.
The same ApplePayButtonComponent handles both 3DS and non-3DS flows automatically. The SDK and backend determine the appropriate authentication level for each transaction.
The SDK automatically evaluates whether 3DS authentication is required for each transaction based on:
- Transaction amount: Higher amounts typically trigger 3DS.
- Risk assessment: Transaction and customer risk scores.
- Regulatory requirements: Strong Customer Authentication (SCA) mandates in regions like Europe.
- Merchant configuration: Your 3DS settings in the Unity Portal.
- Issuer requirements: Bank policies for authentication.
- Apple Pay security: Built-in biometric authentication may reduce 3DS requirements.
When you configure merchantCapabilities: ['supports3DS'] in your Apple Pay setup, you enable the SDK to apply 3DS authentication automatically when needed.
For low-risk transactions, 3DS authentication completes automatically in the background without customer interaction:
- The customer authorises the payment with Touch ID/Face ID in the Apple Pay sheet.
- 3DS authentication evaluates transaction risk using Apple Pay data.
- Authentication completes automatically (low risk detected).
- The transaction proceeds to authorisation immediately.
This flow is common with Apple Pay because the biometric authentication provides strong security signals that reduce perceived risk.
For higher-risk transactions, additional verification may be required:
- The customer authorises the payment with Touch ID/Face ID in the Apple Pay sheet.
- 3DS authentication evaluates transaction risk.
- Additional verification is required (e.g., OTP from the customer's bank).
- The customer completes the challenge.
- The transaction proceeds to authorisation.
Challenge flows are less common with Apple Pay due to its inherent security features.
The Apple Pay payment flow consists of seven key steps, with 3DS evaluation happening automatically in the middle.
The customer authorises payment using Touch ID, Face ID, or passcode in the Apple Pay sheet. Apple's built-in validation occurs within the payment sheet. If validation passes, the payment token is generated.
The SDK automatically evaluates whether 3DS authentication is required based on:
- Transaction amount and risk assessment.
- Merchant configuration and regulatory requirements.
- Apple Pay's built-in security (biometric authentication).
- Issuer policies and customer history.
The Apple Pay payment token is processed and prepared. The token contains encrypted payment data that will be used in the payment flow, with or without 3DS authentication.
The onPreAuthorisation callback is triggered, allowing you to provide additional transaction data such as risk screening data or address verification information. You then decide whether to proceed or cancel the transaction.
After evaluating transaction details, use the Modify Session API to update the authorisation decision on your backend before returning from this callback. Set "authorisation": true in the session data to proceed with the transaction.
If 3DS is required, authentication occurs automatically:
- Frictionless: Authentication completes in the background using Apple Pay security signals.
- Challenge: Customer may be prompted for additional verification (less common with Apple Pay).
If 3DS isn't required, this step is skipped entirely.
The SDK sends the authorisation request to the payment gateway, including:
- The Apple Pay payment token.
- 3DS authentication data (if 3DS was performed).
- The risk screening results.
- The address verification results.
The transaction is either approved or declined by the issuer.
The onPostAuthorisation callback receives transaction identifiers, which you use to retrieve the full authorisation details from your backend:
- Transaction IDs for order tracking.
- The authorisation status (approved/declined).
- 3DS authentication results (if applicable).
- Payment processing details.
Here's a minimal example showing Apple Pay with 3DS support:
import { PxpCheckout } from 'pxp-checkout-sdk';
// Initialise SDK
const pxpSdk = PxpCheckout.initialize({
environment: 'test',
session: {
sessionId: 'your-session-id',
allowedFundingTypes: {
wallets: {
applePay: {
merchantId: 'merchant.com.yourcompany.yourapp'
}
}
}
},
ownerId: 'your-owner-id',
ownerType: 'Merchant',
transactionData: {
currency: 'USD',
amount: 99.99,
merchantTransactionId: 'txn-' + Date.now(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: 'Purchase'
}
},
onGetShopper: () => {
return Promise.resolve({
id: 'shopper-123',
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
});
}
});
// Create Apple Pay component
const applePayComponent = pxpSdk.create('apple-pay-button', {
merchantDisplayName: 'Your Store',
paymentDescription: 'Purchase from Your Store',
usingCss: false,
paymentRequest: {
countryCode: 'US',
currencyCode: 'USD',
// Enable 3DS support - SDK applies it automatically when needed
merchantCapabilities: ['supports3DS', 'supportsEMV'],
supportedNetworks: ['visa', 'masterCard', 'amex'],
total: {
label: 'Total',
amount: '99.99'
}
},
onPostAuthorisation: async (data) => {
// Retrieve full authorisation result from backend
const result = await fetch(`/api/transactions/${data.merchantTransactionId}`);
const transactionData = await result.json();
if (transactionData.status === 'Authorised') {
window.location.href = `/payment-success?txn=${data.merchantTransactionId}`;
} else {
alert('Payment declined. Please try again.');
}
}
});
// Mount the component
applePayComponent.mount('apple-pay-container');The Apple Pay component supports various callback events that allow you to customise the payment flow:
onPreAuthorisation: Provide risk screening data, address verification, and control whether to proceed with authorisation.onPostAuthorisation: Handle authorisation results and retrieve full transaction details from your backend.onShippingContactSelected: Update totals based on shipping address changes.onShippingMethodSelected: Update totals when shipping methods change.onPaymentMethodSelected: Handle payment method changes.onError: Handle errors during the payment process.onCancel: Handle when customers cancel the payment.
For detailed information about all available events, including parameters, return values, and comprehensive examples, see the Events page.
This example demonstrates Apple Pay with risk screening and proper error handling:
import { PxpCheckout } from 'pxp-checkout-sdk';
// Initialise SDK
const pxpSdk = PxpCheckout.initialize({
environment: 'test',
session: {
sessionId: 'your-session-id',
allowedFundingTypes: {
wallets: {
applePay: {
merchantId: 'merchant.com.yourcompany.yourapp'
}
}
}
},
ownerId: 'your-owner-id',
ownerType: 'Merchant',
transactionData: {
currency: 'USD',
amount: 149.99,
merchantTransactionId: 'txn-' + Date.now(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: 'Purchase'
}
},
onGetShopper: () => {
return Promise.resolve({
id: 'shopper-123',
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
});
}
});
// Create Apple Pay component
const applePayComponent = pxpSdk.create('apple-pay-button', {
merchantDisplayName: 'Your Store',
paymentDescription: 'Premium Product Purchase',
usingCss: false,
paymentRequest: {
countryCode: 'US',
currencyCode: 'USD',
merchantCapabilities: ['supports3DS', 'supportsEMV'],
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
total: {
label: 'Your Store',
amount: '149.99'
},
lineItems: [
{ label: 'Premium Product', amount: '140.00' },
{ label: 'Shipping', amount: '5.00' },
{ label: 'Tax', amount: '4.99' }
]
},
onPreAuthorisation: async () => {
// Provide fraud detection data
return {
riskScreeningData: {
performRiskScreening: true,
deviceSessionId: await getKountSessionId(),
items: [{
price: 140.00,
quantity: 1,
category: 'Electronics',
sku: 'PREM-001'
}],
transaction: {
subtotal: 140.00
}
},
addressVerification: {
countryCode: 'US',
postalCode: '10001'
}
};
},
onPostAuthorisation: async (data) => {
try {
// Retrieve full authorisation result from backend
const response = await fetch(`/api/transactions/${data.merchantTransactionId}`);
const result = await response.json();
if (result.status === 'Authorised') {
// Check if 3DS was applied
if (result.threeDSecureResult) {
console.log('Payment authorised with 3DS');
console.log('ECI:', result.threeDSecureResult.eci);
} else {
console.log('Payment authorised without 3DS (low risk)');
}
// Redirect to success page
window.location.href = `/payment-success?txn=${data.merchantTransactionId}`;
} else {
alert('Payment declined. Please try a different payment method.');
}
} catch (error) {
console.error('Failed to retrieve authorisation result:', error);
alert('Unable to confirm payment status. Please contact support.');
}
},
onError: (error) => {
console.error('Apple Pay error:', error);
if (!error.message.includes('User cancelled')) {
alert('Payment error. Please try again.');
}
}
});
// Mount the component
applePayComponent.mount('apple-pay-container');
// Helper function for fraud detection
async function getKountSessionId() {
// Implement device fingerprinting with Kount
return 'device-session-' + Date.now();
}