Full Integration Example
Two ready-to-run snippets: pick the one that matches your backend.
- Basic: the order ID (
invoiceId) is known at page-load time. Pass it toinit()and you are done. - CMS pattern: the order does not exist yet at page-load (typical for WooCommerce, Magento, OpenCart, custom platforms). When the customer taps the Alipay+ button, your backend creates the order and returns the resulting
invoiceId(and a fresh access token, if needed) throughonBeforeProcessPayment.
Both snippets pass paymentData (with amount + currency) and token to init(). The component opens a QR modal with a built-in countdown (default 15 minutes).
If the cart amount can change after the button is rendered (quantity edits, coupons), you have two options:
- Fetch values on every click. Skip
paymentDataandtokenatinit()entirely; return fresh values fromonBeforeProcessPaymentbased on the current cart state. This is the simplest path for highly dynamic carts, no re-init needed. - Re-initialize on change. If you do pass
paymentDataandtokenatinit(), callinit()again with fresh values whenever the cart changes. The access token is minted for the values you passed and the backend rejects mismatches.
- Basic
- CMS pattern
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src='https://test-pay.dnapayments.com/components/alipay-wechat-pay/alipay-wechat-pay-component.js'></script>
<script>
async function renderAlipayPlus() {
const token = 'YOUR_ACCESS_TOKEN';
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'
}]
};
const events = {
onClick: () => {
console.log('Alipay+ button clicked');
},
onError: (error) => {
console.error('Alipay+ error:', error);
},
onCancel: () => {
console.log('Payment cancelled');
},
onPaymentSuccess: (result) => {
console.log('Payment processed', result);
window.location.href = '/success';
}
};
window.DNAPayments.AlipayPlusComponent.init({
containerElement: document.getElementById('alipay-plus-btn-container'),
paymentData,
events,
token,
paymentTimeoutInSeconds: 900 // optional, default
});
}
window.addEventListener('load', renderAlipayPlus);
</script>
</head>
<body>
<div id='alipay-plus-btn-container' style='width: 100%; height: 46px;'></div>
</body>
</html>
Use this shape when the order is created server-side at the moment the customer commits to pay. After the customer taps the Alipay+ button, onBeforeProcessPayment calls your backend to create the order, gets a freshly minted access token bound to the new invoiceId, and returns both to the component. The component then opens the QR modal using these refreshed values.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src='https://test-pay.dnapayments.com/components/alipay-wechat-pay/alipay-wechat-pay-component.js'></script>
<script>
async function renderAlipayPlus() {
// paymentData passed at init() does NOT contain invoiceId yet.
// amount and currency are required so the access token can be bound
// to the correct total.
const paymentData = {
amount: 24,
currency: 'GBP',
description: 'Shoes',
paymentSettings: {
terminalId: 'YOUR_TERMINAL_ID',
callbackUrl: 'https://example.com/callback',
failureCallbackUrl: 'https://example.com/failure-callback'
},
customerDetails: {
accountDetails: { accountId: 'uuid000001' },
billingAddress: { country: 'GB' }
},
orderLines: [{
name: 'Running shoe',
quantity: 1,
unitPrice: 24,
taxRate: 20,
totalAmount: 24,
totalTaxAmount: 4
}]
};
const events = {
onClick: () => {
console.log('Alipay+ button clicked');
},
// Fires after the click and before the QR is requested.
// The server creates the order and issues a token bound to it,
// then returns the refreshed paymentData and token. The locked
// fields (amount, currency, delivery address) must match init().
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
};
},
onPaymentSuccess: (result) => {
console.log('Payment processed', result);
window.location.href = '/success';
},
onCancel: () => {
console.log('Payment cancelled');
},
onError: (error) => {
console.error('Alipay+ error:', error);
}
};
window.DNAPayments.AlipayPlusComponent.init({
containerElement: document.getElementById('alipay-plus-btn-container'),
paymentData,
events,
token: 'BOOTSTRAP_ACCESS_TOKEN' // replaced by the one returned from onBeforeProcessPayment
});
}
window.addEventListener('load', renderAlipayPlus);
</script>
</head>
<body>
<div id='alipay-plus-btn-container' style='width: 100%; height: 46px;'></div>
</body>
</html>
Replace the script source with the production CDN before going live:
<script src='https://pay.dnapayments.com/components/alipay-wechat-pay/alipay-wechat-pay-component.js'></script>
See Deployment for the full go-live checklist.