Skip to main content

Integration

This guide walks you through embedding the Apple Pay button on your page. The flow is:

  1. Load the component script.
  2. Add a container element.
  3. Define event handlers.
  4. Build the paymentData object.
  5. Call init(options).

For a copy-paste-ready end-to-end snippet, jump to the Full Example.

Step 1: Add the Apple Pay Component script

Include the component bundle in the <head> of your HTML page.

Sandbox / Test:

<script src='https://test-pay.dnapayments.com/components/apple-pay/apple-pay-component.js'></script>

Production:

<script src='https://pay.dnapayments.com/components/apple-pay/apple-pay-component.js'></script>

The script exposes window.DNAPayments.ApplePayComponent.

Step 2: Create the container element

<div id='apple-pay-btn-container' style='width: 100%; height: 46px;'></div>

Apply the desired width and height to the container: the button takes the container's dimensions.

Step 3: Gate the render with isAvailable()

DNAPayments.ApplePayComponent.isAvailable() returns a Promise<boolean> that resolves to true only when the device supports Apple Pay and can make payments. Always gate init() behind it so non-supported devices (Android, unsupported browsers) never see a broken button:

async function renderApplePay() {
if (!await window.DNAPayments.ApplePayComponent.isAvailable()) {
return; // device cannot make Apple Pay payments
}
// ...continue with init() below
}

Step 4: Define event handlers

The component is event-driven. Provide callbacks via the events object passed to init(). The full list is in the Events section; the most common four are shown here.

function onClick() {
console.log('Apple Pay button has been clicked');
}

function onError(error) {
// error is { code, message }; see the Handling Error Codes page
console.error('Apple Pay error:', error);
}

function onCancel() {
console.log('Payment was cancelled by the user');
}

function onPaymentSuccess(result) {
console.log('Payment processed successfully', result);
// redirect to a success page, persist invoiceId, etc.
}

const events = {
onClick,
onError,
onCancel,
onPaymentSuccess,
};

Step 5: Build paymentData

paymentData carries the order details. Top-level fields and nested structures are described in paymentData reference.

const paymentData = {
amount: 24,
currency: 'GBP',
invoiceId: 'YOUR_INVOICE_ID',
description: 'Shoes',
paymentSettings: {
terminalId: 'YOUR_TERMINAL_ID',
callbackUrl: 'https://example.com/callback',
failureCallbackUrl: 'https://example.com/failure-callback'
},
customerDetails: {
accountDetails: { accountId: 'uuid000001' },
billingAddress: {
firstName: 'John', lastName: 'Doe',
addressLine1: 'Fulham Rd',
postalCode: 'SW6 1HS', city: 'London', country: 'GB'
},
email: 'example@email.com',
mobilePhone: '+441234567890'
},
orderLines: [{
name: 'Running shoe',
quantity: 1,
unitPrice: 24,
taxRate: 20,
totalAmount: 24,
totalTaxAmount: 4,
imageUrl: 'https://www.example.com/logo.png',
productUrl: 'https://www.example.com/AD6654412.html'
}]
};

Step 6: Initialize the button

Pass the container, paymentData, events and your access token to init():

async function renderApplePay() {
if (!await window.DNAPayments.ApplePayComponent.isAvailable()) return;

window.DNAPayments.ApplePayComponent.init({
containerElement: document.getElementById('apple-pay-btn-container'),
paymentData,
events,
token: 'YOUR_ACCESS_TOKEN',
});
}

window.addEventListener('load', renderApplePay);
Access token

The OAuth token endpoint returns an object (access_token, expires_in, token_type, ...). Pass only the access_token string to the component. See Authentication for the token flow and the scopes required for the seamless component.

API reference

The component exposes the following functions on window.DNAPayments.ApplePayComponent:

MethodDescription
init(options)Render the button and return the component instance.
isAvailable()Promise<boolean>: true if the device can make Apple Pay payments.
create(...)⚠️ Deprecated: use init() instead.

isAvailable()

const ok = await window.DNAPayments.ApplePayComponent.isAvailable();

Resolves to true if Apple Pay is supported and the device can make payments.

init(options)

const component = window.DNAPayments.ApplePayComponent.init(options);

Renders the Apple Pay button into containerElement and returns the initialized component instance.

options fields

PropertyTypeRequiredDescription
containerElementHTMLElementDOM node where the button is rendered.
eventsobjectEvent handler map: see Events.
paymentDataobjectPayment request: see paymentData reference. Must include at least amount and currency so the Apple Pay sheet can display the total.
tokenstringOAuth2 access token (the access_token string returned by Authentication).
environmentstring-Either 'sandbox' or 'production'. Optional, defaults to the environment baked into the bundle (test bundle → sandbox, production bundle → production).
cardBrandsstring[]-Restrict accepted card networks. Defaults to ['VISA', 'MASTERCARD']. Allowed values: 'VISA', 'MASTERCARD', 'AMEX', 'DISCOVER', 'INTERAC', 'JCB'.
localestring-Locale applied to the Apple Pay button (e.g. 'en-GB', 'de-DE'). Defaults to 'en-GB'. Does not affect the Apple Pay sheet: the sheet always follows the user's device language.
domainNamestring-Override for the domain used for merchant validation. Pass this only if the SDK's auto-detected host does not match the domain registered in the portal. The provided host must be registered in the relevant portal (see Prerequisites).

create(...) (deprecated)

Deprecated

create() is kept for backwards compatibility and will be removed in a future version. Use init(options) instead.

Migration:

// Before: positional arguments
window.DNAPayments.ApplePayComponent.create(
container, paymentData, events, token, payload, cardBrands
);

// After: single options object
window.DNAPayments.ApplePayComponent.init({
containerElement: container,
paymentData, events, token, payload, cardBrands
});

Events

The component emits the following events. All handlers are attached via the events map passed to init().

EventSignatureFires when
onClick() => voidThe user taps the Apple Pay button, before the sheet is shown.
onLoad() => voidFires after the button has been rendered and mounted into containerElement. Does not fire on devices where Apple Pay is unavailable; in that case init() simply renders nothing. Use isAvailable() to check support before relying on this event.
onPaymentSuccess(result) => voidThe payment has been processed successfully. See onPaymentSuccess payload.
onError(error) => voidAny error during initialization or processing. See onError payload and Handling Error Codes.
onCancel() => voidThe user dismisses the Apple Pay sheet.
onBeforeProcessPaymentasync functionFires after the user authorizes the payment but before the component executes it on the backend. Optionally return a paymentData object enriched with server-side fields that did not exist at button-render time, most commonly an invoiceId (order ID) created by your CMS at the moment of payment. See onBeforeProcessPayment example.

onError payload

{
code: number,
message: string,
additionalInfo?: any
}

additionalInfo carries the underlying cause when available (the original exception, or the response body from the DNA Payments backend), useful for logging and debugging. See Handling Error Codes for the full list of code values.

onPaymentSuccess payload

{
id: string,
reference: string,
success: boolean
}

The object may include additional fields when applicable.

onBeforeProcessPayment example

The hook fires after the user authorizes the payment in the Apple Pay sheet but before the component executes the charge on our backend. By that point the sheet has already displayed the total and the user has approved it via Touch ID / Face ID, so amount and currency are locked in.

The typical use case is CMS-style integrations (WooCommerce, Magento, OpenCart, custom platforms) where the order does not exist as a database record at button-render time: it is only created on the merchant's backend at the moment of payment. The hook gives you exactly that point in the flow to create the order and return its ID:

const events = {
onBeforeProcessPayment: async (payment) => {
// Create the order on your backend now that the customer has authorized payment.
const { orderId } = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ applePayPayment: payment })
}).then(r => r.json());

// Return paymentData enriched with the freshly created order ID.
// The amount, currency and delivery address must match init() values.
return {
paymentData: {
...initialPaymentData,
invoiceId: orderId
}
};
},
onPaymentSuccess: (result) => { /* ... */ },
onError: (error) => { /* ... */ }
};

If you do not need to enrich paymentData, simply omit the hook or return undefined: the component proceeds with the values from init().

Locked fields

The component compares the returned paymentData against the values used at init() and raises 1010 PAYMENT_DATA_MISMATCH if any of these differ:

  • amount
  • currency
  • customerDetails.deliveryDetails.deliveryAddress (postalCode + addressLine1 + addressLine2)

This guard prevents silent tampering with the value the user just approved on screen. Use the hook to add server-side fields (invoiceId, dynamic paymentSettings.callbackUrl, etc.), not to change the displayed total.

paymentData reference

The most commonly used fields of paymentData:

FieldRequiredDescription
amountTotal transaction amount as a decimal number.
currency-ISO 4217 currency code (e.g. 'GBP'). Defaults to 'GBP'.
invoiceId-Your internal order / invoice identifier.
description-Human-readable description shown on receipts.
paymentSettings.terminalIdYour DNA Payments terminal ID.
paymentSettings.callbackUrl-Server-to-server success callback.
paymentSettings.failureCallbackUrl-Server-to-server failure callback.
customerDetails.accountDetails.accountId-Stable customer ID on your side.
customerDetails.email-Customer email.
customerDetails.mobilePhone-Customer phone.
customerDetails.billingAddress-Billing address object (firstName, lastName, addressLine1, postalCode, city, country, ...). The country defaults to 'GB' when omitted.
customerDetails.deliveryDetails.deliveryAddress-Shipping address object (same shape as billingAddress).
orderLines-Array of line items (name, quantity, unitPrice, taxRate, totalAmount, totalTaxAmount, imageUrl, productUrl).

Once everything is wired up, continue to Full Example, Testing, and Handling Error Codes.