Integration
This guide walks you through embedding the PayPal button on your page. The flow is:
- Load the component script.
- Add a container element.
- Define event handlers.
- Build the
paymentDataobject. - Call
init(options).
For a copy-paste-ready end-to-end snippet, jump to the Full Example.
Step 1: Add the PayPal Component script
Include the component bundle in the <head> of your HTML page.
Sandbox / Test:
<script src='https://test-pay.dnapayments.com/components/paypal/paypal-component.js'></script>
Production:
<script src='https://pay.dnapayments.com/components/paypal/paypal-component.js'></script>
The script exposes window.DNAPayments.PayPalComponent.
Step 2: Create the container element
<div id='paypal-btn-container' style='width: 100%;'></div>
The button takes the container's width. The official PayPal Smart Payment Button is rendered inside.
Step 3: Define event handlers
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('PayPal button has been clicked');
}
function onError(error) {
// error is { code, message, additionalInfo? }, see the Handling Error Codes page
console.error('PayPal 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 4: 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 5: Initialize the button
Pass the container, terminalId, paymentData, events and your access token to init():
async function renderPayPal() {
window.DNAPayments.PayPalComponent.init({
containerElement: document.getElementById('paypal-btn-container'),
terminalId: 'YOUR_TERMINAL_ID',
paymentData,
events,
token: 'YOUR_ACCESS_TOKEN',
});
}
window.addEventListener('load', renderPayPal);
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.
Payment flow
The PayPal Smart Payment Button is rendered by the official PayPal JS SDK, loaded under the hood with the merchant's clientId and merchantId from the terminal configuration. The flow looks like this:
- The component fetches the terminal configuration from DNA Payments and renders the PayPal button into
containerElement. - The customer clicks the button. The component creates the order on the DNA Payments backend (running
onBeforeProcessPaymentfirst, if defined), then hands the order ID to PayPal. - PayPal opens its checkout window. The customer logs in and approves the payment.
- The component approves the order on the DNA Payments backend and fires
onPaymentSuccess. - If the customer closes the PayPal window before approving,
onCancelfires. - If anything goes wrong,
onError({ code, message, additionalInfo? })fires with the relevant code from Handling Error Codes.
API reference
The component exposes a single function on window.DNAPayments.PayPalComponent:
init(options)
const component = await window.DNAPayments.PayPalComponent.init(options);
Fetches the terminal configuration, loads the PayPal JS SDK and renders the PayPal Smart Payment Button into containerElement. Returns the initialized component instance.
options fields
| Property | Type | Required | Description |
|---|---|---|---|
containerElement | HTMLElement | ✅ | DOM node where the button is rendered. |
terminalId | string | ✅ | Your DNA Payments terminal ID. Required to fetch the terminal-side PayPal configuration. |
events | object | - | Event handler map: see Events. |
paymentData | object | - | Payment request: see paymentData reference. Required if not returned from onBeforeProcessPayment. |
token | string | - | OAuth2 access token (the access_token string returned by Authentication). Required if not returned from onBeforeProcessPayment. |
language | string | - | Language of the PayPal button UI. |
environment | string | - | Either 'sandbox' or 'production'. Optional, defaults to the environment baked into the bundle. |
buttonStyle | object | - | Override for the PayPal button style passed straight through to paypal.Buttons({ style }). See PayPal's style reference. |
Events
The component emits the following events. All handlers are attached via the events map passed to init().
| Event | Signature | Fires when |
|---|---|---|
onClick | () => void | The user clicks the PayPal button, before the PayPal checkout window opens. |
onLoad | () => void | Fires after the PayPal button has been rendered and mounted into containerElement. |
onBeforeProcessPayment | async () => { paymentData?, token? } | Fires right after the click, before the order is created on the DNA Payments backend and before PayPal opens its checkout window. The handler may return refreshed paymentData and / or token: this is the canonical CMS pattern where the order (and invoiceId) is created server-side at this moment. Locked fields (amount, currency, delivery address) must match the init() values, otherwise the component fires 1017. See Deferred values via onBeforeProcessPayment. |
onPaymentSuccess | (result) => void | The order has been approved on the DNA Payments backend. See onPaymentSuccess payload. |
onCancel | () => void | The customer closed or cancelled the PayPal checkout window. |
onError | (error) => void | Any error during initialization or processing. See onError payload and Handling Error Codes. |
Deferred values via onBeforeProcessPayment
onBeforeProcessPayment fires right after the click, before the order is created on the DNA Payments backend and before PayPal opens its checkout window. The handler can return { paymentData, token } to swap in server-side values (typically invoiceId and a freshly issued access token):
const events = {
onBeforeProcessPayment: async () => {
const { invoiceId, token } = await fetch('/api/create-order-and-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: paymentData.amount, currency: paymentData.currency })
}).then(r => r.json());
return {
paymentData: { ...paymentData, invoiceId },
token
};
}
};
Locked fields (amount, currency, delivery address) must match the values passed at init(). Returning a paymentData whose locked fields differ fires 1017 PAYMENT_DATA_MISMATCH. Use onBeforeProcessPayment to add server-side fields, not to change the displayed total. If the cart amount can change, re-initialize the component instead.
onPaymentSuccess payload
{
id: string,
reference: string,
success: boolean
}
The object may include additional fields when applicable.
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.
paymentData reference
The most commonly used fields of paymentData:
| Field | Required | Description |
|---|---|---|
amount | ✅ | Total 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.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.billingAddress | - | Billing address object (firstName, lastName, addressLine1, postalCode, city, country, ...). |
customerDetails.deliveryDetails.deliveryAddress | - | Shipping address. Including this enables shipping in the PayPal flow; omitting it switches PayPal to NO_SHIPPING. |
orderLines | - | Array of line items (name, quantity, unitPrice, taxRate, totalAmount, totalTaxAmount, imageUrl, productUrl). |
transactionType | - | Override for the transaction type. Defaults to the value configured on the terminal. |