@paydock/client-sdk 1.139.0 → 1.140.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +2573 -0
  2. package/bundles/index.cjs +1296 -508
  3. package/bundles/index.cjs.d.ts +1377 -200
  4. package/bundles/index.mjs +1295 -509
  5. package/bundles/index.mjs.d.ts +1377 -200
  6. package/bundles/types/checkout/checkout.d.ts.map +1 -1
  7. package/bundles/types/checkout/v1/instructions/instruction.card_form.show.d.ts.map +1 -1
  8. package/bundles/types/checkout/v3/instructions/instruction.card_form.show.d.ts.map +1 -1
  9. package/bundles/types/checkout/v3/instructions/instruction.payment_methods.show.d.ts.map +1 -1
  10. package/bundles/types/checkout-button/zipmoney/zipmoney-contextual.runner.d.ts +1 -2
  11. package/bundles/types/checkout-button/zipmoney/zipmoney-contextual.runner.d.ts.map +1 -1
  12. package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts +70 -0
  13. package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts.map +1 -0
  14. package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts +242 -74
  15. package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts.map +1 -1
  16. package/bundles/types/open-wallets/base/open-wallet.service.d.ts +62 -4
  17. package/bundles/types/open-wallets/base/open-wallet.service.d.ts.map +1 -1
  18. package/bundles/types/open-wallets/enum/error-operation.enum.d.ts +15 -0
  19. package/bundles/types/open-wallets/enum/error-operation.enum.d.ts.map +1 -0
  20. package/bundles/types/open-wallets/enum/event.enum.d.ts +11 -3
  21. package/bundles/types/open-wallets/enum/event.enum.d.ts.map +1 -1
  22. package/bundles/types/open-wallets/enum/token-type.enum.d.ts +10 -0
  23. package/bundles/types/open-wallets/enum/token-type.enum.d.ts.map +1 -0
  24. package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts +65 -0
  25. package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts.map +1 -0
  26. package/bundles/types/open-wallets/index.d.ts +293 -0
  27. package/bundles/types/open-wallets/index.d.ts.map +1 -1
  28. package/bundles/types/open-wallets/interfaces/events.interface.d.ts +87 -14
  29. package/bundles/types/open-wallets/interfaces/events.interface.d.ts.map +1 -1
  30. package/bundles/types/open-wallets/interfaces/google-pay/google-pay-meta.interface.d.ts +6 -0
  31. package/bundles/types/open-wallets/interfaces/google-pay/google-pay-meta.interface.d.ts.map +1 -1
  32. package/bundles/types/open-wallets/interfaces/index.d.ts +2 -2
  33. package/bundles/types/open-wallets/interfaces/index.d.ts.map +1 -1
  34. package/bundles/types/open-wallets/interfaces/open-wallet-meta.interface.d.ts +12 -0
  35. package/bundles/types/open-wallets/interfaces/open-wallet-meta.interface.d.ts.map +1 -1
  36. package/bundles/types/open-wallets/interfaces/payment-source.interface.d.ts +28 -2
  37. package/bundles/types/open-wallets/interfaces/payment-source.interface.d.ts.map +1 -1
  38. package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts +27 -2
  39. package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts.map +1 -1
  40. package/bundles/types/open-wallets/services/google-pay/constants/google-pay.constants.d.ts +9 -0
  41. package/bundles/types/open-wallets/services/google-pay/constants/google-pay.constants.d.ts.map +1 -1
  42. package/bundles/types/open-wallets/services/google-pay/google-pay.open-wallet.service.d.ts +20 -9
  43. package/bundles/types/open-wallets/services/google-pay/google-pay.open-wallet.service.d.ts.map +1 -1
  44. package/bundles/types/open-wallets/services/google-pay/utils/google-pay.utils.d.ts +45 -0
  45. package/bundles/types/open-wallets/services/google-pay/utils/google-pay.utils.d.ts.map +1 -1
  46. package/bundles/types/open-wallets/services/google-pay/utils/index.d.ts +1 -1
  47. package/bundles/types/open-wallets/services/google-pay/utils/index.d.ts.map +1 -1
  48. package/bundles/types/open-wallets/services/google-pay/validation/google-pay.validation.d.ts +13 -0
  49. package/bundles/types/open-wallets/services/google-pay/validation/google-pay.validation.d.ts.map +1 -1
  50. package/bundles/types/open-wallets/types/base-event-data.interface.d.ts +24 -2
  51. package/bundles/types/open-wallets/types/base-event-data.interface.d.ts.map +1 -1
  52. package/bundles/types/open-wallets/types/index.d.ts +2 -1
  53. package/bundles/types/open-wallets/types/index.d.ts.map +1 -1
  54. package/bundles/types/open-wallets/types/on-shipping-address-change-event-data.interface.d.ts +16 -2
  55. package/bundles/types/open-wallets/types/on-shipping-address-change-event-data.interface.d.ts.map +1 -1
  56. package/bundles/types/open-wallets/types/on-shipping-address-change-event-response.interface.d.ts +20 -2
  57. package/bundles/types/open-wallets/types/on-shipping-address-change-event-response.interface.d.ts.map +1 -1
  58. package/bundles/types/open-wallets/types/on-shipping-option-change-event-data.interface.d.ts +13 -2
  59. package/bundles/types/open-wallets/types/on-shipping-option-change-event-data.interface.d.ts.map +1 -1
  60. package/bundles/types/open-wallets/types/on-shipping-option-change-event-response.interface.d.ts +12 -0
  61. package/bundles/types/open-wallets/types/on-shipping-option-change-event-response.interface.d.ts.map +1 -1
  62. package/bundles/types/open-wallets/types/payment-source.type.d.ts +3 -2
  63. package/bundles/types/open-wallets/types/payment-source.type.d.ts.map +1 -1
  64. package/bundles/types/open-wallets/types/shipping-event-to-response.type.d.ts +8 -0
  65. package/bundles/types/open-wallets/types/shipping-event-to-response.type.d.ts.map +1 -1
  66. package/bundles/widget.umd.js +1296 -508
  67. package/bundles/widget.umd.js.d.ts +1377 -200
  68. package/bundles/widget.umd.js.min.d.ts +1377 -200
  69. package/bundles/widget.umd.min.js +1 -1
  70. package/docs/open-wallet-buttons-examples.md +561 -830
  71. package/docs/open-wallet-buttons.md +1652 -0
  72. package/package.json +1 -1
  73. package/slate.md +1673 -0
package/slate.md CHANGED
@@ -1311,6 +1311,1679 @@ Similarly, for **GooglePay via MPGS** you can initialize the `PaymentMethodSpeci
1311
1311
  </html>
1312
1312
  ```
1313
1313
 
1314
+ ## Express Wallet Buttons
1315
+
1316
+ Express Wallet Buttons allow to integrate with E-Wallets in an "express" operational mode, allowing to show the respective button in product or cart pages.
1317
+
1318
+ The general flow to use the widgets is:
1319
+ 1. Configure your gateway and connect it using Paydock API or Dashboard.
1320
+ 2. Create a container in your site
1321
+ ```html
1322
+ <div id="widget"></div>
1323
+ ```
1324
+ 3. Initialize the specific WalletButtonExpress, providing your Access Token (preferred) or Public Key, plus required and optional meta parameters for the wallet in use. The general format is:
1325
+ ```js
1326
+ new paydock.{Provider}WalletButtonExpress(
1327
+ "#widget",
1328
+ accessTokenOrPublicKey,
1329
+ gatewayId,
1330
+ gatewaySpecificMeta,
1331
+ );
1332
+ ```
1333
+ 4. (optional) If the screen where the button is rendered allows for cart/amount changes, call `setMeta` method to update the meta information.
1334
+ 5. Handle the `onClick` callback, where you should call your server, initialize the wallet charge via `POST v1/charges/wallet` and return the wallet token.
1335
+ 6. Handle the `onPaymentSuccessful`, `onPaymentError` and `onPaymentInReview` (if fraud is applicable) for payment results.
1336
+
1337
+ ### Supported Providers
1338
+ 1. [Apple Pay](#apple-pay-wallet-button-express)
1339
+ 2. [Paypal](#paypal-wallet-button-express)
1340
+
1341
+ ### Apple Pay Wallet Button Express
1342
+
1343
+ A full description of the meta parameters for [ApplePayWalletButtonExpress](#ApplePayWalletButtonExpress) meta parameters can be found [here](#ApplePayWalletMeta). Below you will find a fully working html example.
1344
+
1345
+ ```html
1346
+ <!DOCTYPE html>
1347
+ <html lang="en">
1348
+ <head>
1349
+ <meta charset="UTF-8">
1350
+ <title>Title</title>
1351
+ </head>
1352
+ <body>
1353
+ <h2>Payment using PayDock ApplePayWalletButtonExpress!</h2>
1354
+ <div id="widget"></div>
1355
+ </body>
1356
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
1357
+ <script>
1358
+ let button = new paydock.ApplePayWalletButtonExpress(
1359
+ "#widget",
1360
+ accessTokenOrPublicKey,
1361
+ gatewayId,
1362
+ {
1363
+ amount_label: 'TOTAL',
1364
+ country: 'AU',
1365
+ currency: 'AUD',
1366
+ amount: 15.5,
1367
+ // merchant_capabilities: ['supports3DS', 'supportsEMV', 'supportsCredit', 'supportsDebit'],
1368
+ // supported_networks: ['visa', 'masterCard', 'amex', 'chinaUnionPay', 'discover', 'interac', 'jcb', 'privateLabel'],
1369
+ // required_billing_contact_fields: ['email', 'name', 'phone', 'postalAddress'], // phone and email do not work according to relevant testing
1370
+ // required_shipping_contact_fields: ['email', 'phone'], // Workaround to pull phone and email from shipping contact instead - does not require additional shipping address information
1371
+ // supported_countries: ["AU"],
1372
+ // style: {
1373
+ // button_type: "buy",
1374
+ // button_style: "black",
1375
+ // },
1376
+ }
1377
+ );
1378
+
1379
+ button.setEnv('sandbox');
1380
+
1381
+ button.onUnavailable(function() {
1382
+ console.log("Button not available");
1383
+ });
1384
+
1385
+ button.onError(function(error) {
1386
+ console.log("On Error Callback", error);
1387
+ });
1388
+
1389
+ button.onPaymentSuccessful(function(data) {
1390
+ console.log("Payment successful");
1391
+ console.log(data);
1392
+ });
1393
+
1394
+ button.onPaymentError(function(err) {
1395
+ console.log("Payment error");
1396
+ console.log(err);
1397
+ });
1398
+
1399
+ button.onPaymentInReview(function(data) {
1400
+ console.log("The payment is on fraud review");
1401
+ console.log(data);
1402
+ });
1403
+
1404
+ button.onClick(async (data) => {
1405
+ console.log("Button clicked", data);
1406
+
1407
+ const responseData = await fetch('https://your-server-url/initialize-wallet-charge');
1408
+ const parsedData = await responseData.json();
1409
+ return parsedData.resource.data.token;
1410
+ });
1411
+
1412
+ button.onCheckoutClose(() => {
1413
+ console.log("Checkout closed");
1414
+ });
1415
+
1416
+ button.load();
1417
+ </script>
1418
+ </html>
1419
+ ```
1420
+
1421
+ ### Apple Pay Wallet Button Express with Shipping
1422
+
1423
+ A full description of the meta parameters for [ApplePayWalletButtonExpress](#ApplePayWalletButtonExpress) meta parameters can be found [here](#ApplePayWalletMeta). Below you will find a fully working html example.
1424
+
1425
+ ```html
1426
+ <html>
1427
+ <head>
1428
+ <title>Apple Pay Express test page</title>
1429
+ <style>
1430
+ #inputModal {
1431
+ display: none;
1432
+ position: fixed;
1433
+ left: 0;
1434
+ top: 0;
1435
+ width: 100%;
1436
+ height: 100%;
1437
+ background-color: rgba(0,0,0,0.5);
1438
+ z-index: 1000;
1439
+ }
1440
+ #inputBox {
1441
+ position: absolute;
1442
+ left: 50%;
1443
+ top: 50%;
1444
+ transform: translate(-50%, -50%);
1445
+ padding: 20px;
1446
+ background: white;
1447
+ border-radius: 5px;
1448
+ box-shadow: 2px 2px 10px rgba(0,0,0,0.5);
1449
+ }
1450
+ </style>
1451
+ </head>
1452
+ <body>
1453
+ <table id='paymentTable'>
1454
+ <tr>
1455
+ <td>Environment:</td>
1456
+ <td>
1457
+ <select id="environment" name="environment">
1458
+ <option value="sandbox">Sandbox</option>
1459
+ <option value="local">Local</option>
1460
+ </select>
1461
+ </td>
1462
+ </tr>
1463
+ <tr>
1464
+ <td>Access Token / Public Key:</td>
1465
+ <td><input type="text" name="access" id="access" /></td>
1466
+ </tr>
1467
+ <tr>
1468
+ <td>Secret Key:</td>
1469
+ <td><input type="text" name="secretKey" id="secretKey" /></td>
1470
+ </tr>
1471
+ <tr>
1472
+ <td>Gateway Id:</td>
1473
+ <td><input type="text" name="gateway" id="gateway" /></td>
1474
+ </tr>
1475
+ <tr>
1476
+ <td>Wallet Charge - for apple pay we need to add it here because the apple pay popup does not allow us to
1477
+ inject it there but it will be used only on click. So is optional, if not provided it simulates an error
1478
+ when creating B2B wallet charge on click:</td>
1479
+ <td><input type="text" name="token" id="token" /></td>
1480
+ </tr>
1481
+ <tr>
1482
+ <td>Charge id - Used to update the charge with the shipping data/shipping options</td>
1483
+ <td><input type="text" name="chargeId" id="chargeId" /></td>
1484
+ </tr>
1485
+ <tr>
1486
+ <td>Meta:</td>
1487
+ <td><textarea id="meta" name="meta" rows="4" cols="50"></textarea></td>
1488
+ </tr>
1489
+ </table>
1490
+ <div id="button">
1491
+ <input type="submit" name="event" value="Send" class="button" onclick="return loadButtons()" />
1492
+ </div>
1493
+ <div id="widget"></div>
1494
+ </body>
1495
+
1496
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js"></script>
1497
+ <script type=text/javascript>
1498
+ // Environment enum with API URLs
1499
+ const ENVIRONMENTS = {
1500
+ PRODUCTION: {
1501
+ name: 'production',
1502
+ apiUrl: 'https://api.paydock.com'
1503
+ },
1504
+ SANDBOX: {
1505
+ name: 'sandbox',
1506
+ apiUrl: 'https://api-sandox.paydock.com'
1507
+ }
1508
+ };
1509
+
1510
+ // Function to get API URL based on selected environment
1511
+ function getApiUrl(environmentName) {
1512
+ const env = Object.values(ENVIRONMENTS).find(env => env.name === environmentName);
1513
+ return env ? env.apiUrl : ENVIRONMENTS.SANDBOX.apiUrl;
1514
+ }
1515
+
1516
+ // Function to get current base URL from selected environment
1517
+ function getBaseUrl() {
1518
+ const selectedEnvironment = document.getElementById("environment").value;
1519
+ return getApiUrl(selectedEnvironment);
1520
+ }
1521
+
1522
+ async function updateCharge(secretKey, chargeId, updateData) {
1523
+ try {
1524
+ const baseUrl = getBaseUrl();
1525
+ const response = await fetch(`${baseUrl}/v1/charges/wallet/${chargeId}`, {
1526
+ method: 'PUT',
1527
+ headers: {
1528
+ 'x-user-secret-key': secretKey,
1529
+ 'Content-Type': 'application/json',
1530
+ },
1531
+ body: JSON.stringify(updateData),
1532
+ });
1533
+ const data = await response.json();
1534
+ console.log('Update charge response:', data);
1535
+ return data;
1536
+ } catch (error) {
1537
+ console.error('Error updating charge:', error);
1538
+ }
1539
+ };
1540
+
1541
+ const shippingOptions = [
1542
+ {
1543
+ label: "Test 1",
1544
+ detail: "This is a test 1 shipping methods",
1545
+ amount: 10,
1546
+ id: "randomId1",
1547
+ date_components_range: {
1548
+ start_date_components: {
1549
+ years: 0,
1550
+ months: 0,
1551
+ days: 5,
1552
+ hours: 0,
1553
+ },
1554
+ end_date_components: {
1555
+ years: 0,
1556
+ months: 0,
1557
+ days: 10,
1558
+ hours: 0,
1559
+ }
1560
+ }
1561
+ },
1562
+ {
1563
+ label: "Test 2",
1564
+ detail: "This is a test 2 shipping methods",
1565
+ amount: 14,
1566
+ id: "randomId2",
1567
+ date_components_range: {
1568
+ start_date_components: {
1569
+ years: 0,
1570
+ months: 0,
1571
+ days: 6,
1572
+ hours: 0,
1573
+ },
1574
+ end_date_components: {
1575
+ years: 0,
1576
+ months: 0,
1577
+ days: 12,
1578
+ hours: 0,
1579
+ },
1580
+ },
1581
+ },
1582
+ ];
1583
+
1584
+ function loadButtons() {
1585
+ const secretKey = document.getElementById("secretKey").value;
1586
+ if (!secretKey) {
1587
+ alert("Please enter the secret key.");
1588
+ return false;
1589
+ }
1590
+
1591
+ let button = new paydock.ApplePayWalletButtonExpress(
1592
+ "#widget",
1593
+ document.getElementById("access").value,
1594
+ document.getElementById("gateway").value,
1595
+ JSON.parse(document.getElementById("meta").value),
1596
+ );
1597
+
1598
+ button.setEnv(document.getElementById("environment").value);
1599
+
1600
+ let charge_id;
1601
+
1602
+ button.onClick(async (data) => {
1603
+ const { token, chargeId } = await getUserInput();
1604
+ charge_id = chargeId;
1605
+ return token;
1606
+ });
1607
+
1608
+ const amount = JSON.parse(document.getElementById('meta').value).amount;
1609
+
1610
+ button.onUnavailable(function() {
1611
+ console.log("Button unavailable");
1612
+ });
1613
+ button.onError(function(error) {
1614
+ console.log("On Error Callback", error);
1615
+ });
1616
+ button.onPaymentSuccessful(function(data) {
1617
+ console.log("Payment successful");
1618
+ console.log(data);
1619
+ });
1620
+ button.onPaymentError(function(err) {
1621
+ console.log("Payment error");
1622
+ console.log(err);
1623
+ });
1624
+ button.onPaymentInReview(function(data) {
1625
+ console.log("The payment is on fraud review");
1626
+ console.log(data);
1627
+ });
1628
+ button.onCheckoutClose(() => {
1629
+ console.log("Checkout closed");
1630
+ });
1631
+
1632
+ button.onShippingAddressChange(async function(data) {
1633
+ console.log("Shipping address has been updated", data);
1634
+
1635
+ const defaultOption = shippingOptions[0];
1636
+
1637
+ const updateData = {
1638
+ shipping: {
1639
+ ...data.data,
1640
+ amount: defaultOption.amount,
1641
+ method: defaultOption.id,
1642
+ options: shippingOptions,
1643
+ },
1644
+ amount: amount + defaultOption.amount
1645
+ };
1646
+
1647
+ const res = await updateCharge(secretKey, charge_id, updateData);
1648
+ return { token: res.resource.data.token };
1649
+ });
1650
+
1651
+ button.onShippingOptionsChange(async function(data) {
1652
+ console.log("Shipping options have been updated", JSON.stringify(data, null, 2));
1653
+
1654
+ const updateData = {
1655
+ shipping: {
1656
+ method: data.data.shipping_option_id,
1657
+ amount: data.data.amount,
1658
+ },
1659
+ amount: amount + Number(data.data.amount)
1660
+ };
1661
+
1662
+ const res = await updateCharge(secretKey, charge_id, updateData);
1663
+ return { token: res.resource.data.token };
1664
+ });
1665
+
1666
+ button.load()
1667
+
1668
+ document.getElementById("paymentTable").style.display = "none";
1669
+ document.getElementById("button").style.display = "none";
1670
+ return true;
1671
+ }
1672
+
1673
+ function getUserInput(message) {
1674
+ return new Promise((resolve, reject) => {
1675
+ console.log("Simulating B2B call to generate token...");
1676
+ setTimeout(() => {
1677
+ const token = document.getElementById("token").value;
1678
+ const chargeId = document.getElementById("chargeId").value;
1679
+ if (token && chargeId)
1680
+ return resolve({ token, chargeId });
1681
+ return reject("No token or Charge Id provided");
1682
+ }, 2000);
1683
+ });
1684
+ }
1685
+
1686
+ document.addEventListener('DOMContentLoaded', () => {
1687
+ // Function to get the value of a query parameter by name
1688
+ function getQueryParam(name) {
1689
+ const urlParams = new URLSearchParams(window.location.search);
1690
+ return urlParams.get(name);
1691
+ }
1692
+
1693
+ // Function to set input values from URL parameters
1694
+ function setInputValues() {
1695
+ const meta = {
1696
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
1697
+ amount_label: 'TOTAL',
1698
+ country: 'AU',
1699
+ currency: 'AUD',
1700
+ amount: 10,
1701
+ shipping_editing_mode: 'available', // available, store_pickup
1702
+ required_shipping_contact_fields: [
1703
+ 'postalAddress',
1704
+ 'name',
1705
+ 'phone',
1706
+ 'email',
1707
+ ],
1708
+ shipping: {
1709
+ amount: 5,
1710
+ address_line1: "Address Line 1",
1711
+ address_city: "Test Locality",
1712
+ address_state: "NSW",
1713
+ address_country: "Australia",
1714
+ address_country_code: "AU",
1715
+ address_postcode: "3000",
1716
+ contact: {
1717
+ phone: "+61400245562",
1718
+ email: "qa.notifications+appleid@paydock.com",
1719
+ first_name: "QA",
1720
+ last_name: "QA",
1721
+ },
1722
+ options: shippingOptions,
1723
+ },
1724
+ // merchant_capabilities: ['supports3DS', 'supportsEMV', 'supportsCredit', 'supportsDebit'],
1725
+ // supported_networks: ['visa', 'masterCard', 'amex', 'chinaUnionPay', 'discover', 'interac', 'jcb', 'privateLabel'],
1726
+ // required_billing_contact_fields: ['email', 'name', 'phone', 'postalAddress', 'phoneticName'],
1727
+ // required_shipping_contact_fields: ['email', 'phone' /*, 'name', 'postalAddress', 'phoneticName'*/],
1728
+ // supported_countries: [],
1729
+ // style: {
1730
+ // button_type: 'continue',
1731
+ // button_style: 'white',
1732
+ // },
1733
+ };
1734
+ document.getElementById('meta').value = JSON.stringify(meta, null, 2);
1735
+ }
1736
+
1737
+ setInputValues();
1738
+ });
1739
+ </script>
1740
+ </html>
1741
+ ```
1742
+
1743
+ When supporting shipping, the method `onShippingAddressChange` and `onShippingOptionsChange` are required to update the shipping address and options.
1744
+
1745
+ ```javascript
1746
+ button.onShippingAddressChange(async function(data) {
1747
+ console.log("Shipping address has been updated", data);
1748
+
1749
+ const updateData = {
1750
+ shipping: {
1751
+ ...data.data,
1752
+ amount: defaultOption.amount,
1753
+ method: defaultOption.id,
1754
+ options: shippingOptions,
1755
+ },
1756
+ amount: amount + defaultOption.amount
1757
+ };
1758
+
1759
+ const res = await updateCharge(secretKey, charge_id, updateData);
1760
+ return { token: res.resource.data.token };
1761
+ });
1762
+
1763
+ button.onShippingOptionsChange(async function(data) {
1764
+ console.log("Shipping options have been updated", data);
1765
+
1766
+ const updateData = {
1767
+ shipping: {
1768
+ method: data.data.shipping_option_id,
1769
+ amount: data.data.amount,
1770
+ },
1771
+ amount: amount + Number(data.data.amount)
1772
+ };
1773
+
1774
+ const res = await updateCharge(secretKey, charge_id, updateData);
1775
+ return { token: res.resource.data.token };
1776
+ });
1777
+ ```
1778
+
1779
+ The `updateCharge` method is a custom method to update the charge with the shipping data/shipping options. It is not part of the Paydock SDK and it should use the Paydock's public API to update the charge from the merchant's server.
1780
+
1781
+ ### Supported Cases
1782
+ #### Injected Shipping Address, non-editable by the customer
1783
+
1784
+ This is the case where the shipping address is injected by the merchant and is not editable by the customer. The customer can only select the shipping option.
1785
+
1786
+ The required meta parameters for this case are:
1787
+ - shipping_editing_mode: 'store_pickup'
1788
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
1789
+
1790
+ ```javascript
1791
+ meta: {
1792
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
1793
+ amount_label: 'TOTAL',
1794
+ country: 'AU',
1795
+ currency: 'AUD',
1796
+ amount: 10,
1797
+ shipping_editing_mode: 'store_pickup',
1798
+ required_shipping_contact_fields: [
1799
+ 'postalAddress', // At least one of the fields is required so the shipping address is shown at Apple Pay.
1800
+ 'name',
1801
+ 'phone',
1802
+ 'email',
1803
+ ],
1804
+ shipping: {
1805
+ amount: 5,
1806
+ address_line1: "Address Line 1",
1807
+ address_city: "Test Locality",
1808
+ address_state: "NSW",
1809
+ address_country: "Australia",
1810
+ address_country_code: "AU",
1811
+ address_postcode: "3000",
1812
+ contact: {
1813
+ phone: "+61400245562",
1814
+ email: "qa.notifications+appleid@paydock.com",
1815
+ first_name: "QA",
1816
+ last_name: "QA",
1817
+ },
1818
+ options: [
1819
+ {
1820
+ label: "Test 1",
1821
+ detail: "This is a test 1 shipping methods",
1822
+ amount: 10,
1823
+ id: "randomId1",
1824
+ date_components_range: {
1825
+ start_date_components: {
1826
+ years: 0,
1827
+ months: 0,
1828
+ days: 5,
1829
+ hours: 0,
1830
+ },
1831
+ end_date_components: {
1832
+ years: 0,
1833
+ months: 0,
1834
+ days: 10,
1835
+ hours: 0,
1836
+ }
1837
+ }
1838
+ }
1839
+ ],
1840
+ },
1841
+ }
1842
+ ```
1843
+
1844
+ This is the case where the shipping address is injected by the merchant and is editable by the customer. The customer can edit the shipping address and select the shipping option.
1845
+
1846
+ The required meta parameters for this case are:
1847
+ - shipping_editing_mode: 'available'
1848
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
1849
+
1850
+ ```javascript
1851
+ meta: {
1852
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
1853
+ amount_label: 'TOTAL',
1854
+ country: 'AU',
1855
+ currency: 'AUD',
1856
+ amount: 10,
1857
+ shipping_editing_mode: 'available',
1858
+ required_shipping_contact_fields: [
1859
+ 'postalAddress', // At least one of the fields is required so the shipping address is shown at Apple Pay.
1860
+ 'name',
1861
+ 'phone',
1862
+ 'email',
1863
+ ],
1864
+ shipping: {
1865
+ amount: 5,
1866
+ address_line1: "Address Line 1",
1867
+ address_city: "Test Locality",
1868
+ address_state: "NSW",
1869
+ address_country: "Australia",
1870
+ address_country_code: "AU",
1871
+ address_postcode: "3000",
1872
+ contact: {
1873
+ phone: "+61400245562",
1874
+ email: "qa.notifications+appleid@paydock.com",
1875
+ first_name: "QA",
1876
+ last_name: "QA",
1877
+ },
1878
+ options: [
1879
+ {
1880
+ label: "Test 1",
1881
+ detail: "This is a test 1 shipping methods",
1882
+ amount: 10,
1883
+ id: "randomId1",
1884
+ date_components_range: {
1885
+ start_date_components: {
1886
+ years: 0,
1887
+ months: 0,
1888
+ days: 5,
1889
+ hours: 0,
1890
+ },
1891
+ end_date_components: {
1892
+ years: 0,
1893
+ months: 0,
1894
+ days: 10,
1895
+ hours: 0,
1896
+ }
1897
+ }
1898
+ }
1899
+ ],
1900
+ },
1901
+ }
1902
+ ```
1903
+
1904
+ #### Shipping address editable by the customer
1905
+
1906
+ This is the case where the shipping address is not injected by the merchant and is editable by the customer. The customer can edit the shipping address and select the shipping option.
1907
+
1908
+ The required meta parameters for this case are:
1909
+ - shipping_editing_mode: 'available'
1910
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
1911
+
1912
+ ```javascript
1913
+ meta: {
1914
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
1915
+ amount_label: 'TOTAL',
1916
+ country: 'AU',
1917
+ currency: 'AUD',
1918
+ amount: 10,
1919
+ shipping_editing_mode: 'available',
1920
+ required_shipping_contact_fields: [
1921
+ 'postalAddress', // At least one of the fields is required so the shipping address is shown at Apple Pay.
1922
+ 'name',
1923
+ 'phone',
1924
+ 'email',
1925
+ ],
1926
+ }
1927
+ ```
1928
+
1929
+ When the the customer selects an address, the `onShippingAddressChange` method is called with the shipping address data. If the merchant wants to update the charge with the shipping address, it should update the charge using Paydock's public API Update Charge method with the shipping address data.
1930
+
1931
+ It can include the shipping options in the update data, that will be used to show the shipping options in the Apple Pay popup.
1932
+
1933
+ ```javascript
1934
+ button.onShippingAddressChange(async function(data) {
1935
+ console.log("Shipping address has been updated", data);
1936
+
1937
+ const updateData = {
1938
+ shipping: {
1939
+ ...data.data,
1940
+ amount: defaultOption.amount,
1941
+ method: defaultOption.id,
1942
+ options: shippingOptions,
1943
+ },
1944
+ amount: amount + defaultOption.amount
1945
+ };
1946
+ });
1947
+ ```
1948
+
1949
+ #### No shipping address
1950
+
1951
+ This is the case where no shipping address is required at all in the popup (e.g., digital goods, services, or virtual products, or Shipping Address collected separately by the merchant). The "Send to" UI field will not be shown in the Apple Pay sheet, it will be hidden.
1952
+
1953
+ **Important:**
1954
+ - No shipping address should be provided in the meta object.
1955
+ - Shipping address could be provided in the initial POST `/v1/charges/wallet` endpoint, if collected previously.
1956
+
1957
+ The required meta parameters for this case are:
1958
+ - `required_shipping_contact_fields`: Only include contact fields if needed (phone, email), but NOT `postalAddress`.
1959
+
1960
+ ```javascript
1961
+ meta: {
1962
+ "amount_label": "TOTAL",
1963
+ "country": "AU",
1964
+ "currency": "AUD",
1965
+ "amount": 10,
1966
+ "shipping_editing_mode": "available",
1967
+ "required_shipping_contact_fields": ["phone", "email"],
1968
+ "apple_pay_capabilities": ["credentials_available", "credentials_status_unknown", "credentials_unavailable"]
1969
+ }
1970
+ ```
1971
+
1972
+ ### Paypal Wallet Button Express
1973
+ A full description of the meta parameters for [PaypalWalletButtonExpress](#PaypalWalletButtonExpress) meta parameters can be found [here](#PaypalWalletMeta). Below you will find a fully working html example.
1974
+
1975
+ ```html
1976
+ <!DOCTYPE html>
1977
+ <html lang="en">
1978
+ <head>
1979
+ <meta charset="UTF-8">
1980
+ <title>Title</title>
1981
+ </head>
1982
+ <body>
1983
+ <h2>Payment using PayDock PaypalWalletButtonExpress!</h2>
1984
+ <div id="widget"></div>
1985
+ </body>
1986
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
1987
+ <script>
1988
+ let button = new paydock.PaypalWalletButtonExpress(
1989
+ "#widget",
1990
+ accessTokenOrPublicKey,
1991
+ gatewayId,
1992
+ {
1993
+ amount: 15.5,
1994
+ currency: 'AUD',
1995
+ pay_later: false,
1996
+ standalone: false,
1997
+ capture: true,
1998
+ // style: {
1999
+ // layout: 'horizontal', // or 'vertical'
2000
+ // color: 'gold', // or 'blue', 'silver', 'black', 'white'
2001
+ // shape: 'rect', // or 'pill', 'sharp'
2002
+ // borderRadius: 5,
2003
+ // height: 40,
2004
+ // disableMaxWidth: false,
2005
+ // label: 'paypal', // or 'checkout', 'buynow', 'pay', 'installment'
2006
+ // tagline: true,
2007
+ // messages: {
2008
+ // layout: 'text', // or 'flex'
2009
+ // logo: {
2010
+ // type: 'primary', // or 'alternative', 'inline', 'none'
2011
+ // position: 'left', // or 'right', 'top'
2012
+ // },
2013
+ // text: {
2014
+ // color: 'black', // or 'white', 'monochrome', 'grayscale'
2015
+ // size: 10, // or 11, 12, 13, 14, 15, 16
2016
+ // align: 'left', // or 'center', 'right'
2017
+ // },
2018
+ // color: 'blue', // or 'black', 'white', 'white-no-border', 'gray', 'monochrome', 'grayscale'
2019
+ // ratio: '1x1', // or '1x4', '8x1', '20x1'
2020
+ // },
2021
+ // }
2022
+ }
2023
+ );
2024
+
2025
+ button.setEnv('sandbox');
2026
+
2027
+ button.onUnavailable(function() {
2028
+ console.log("Button not available");
2029
+ });
2030
+
2031
+ button.onError(function(error) {
2032
+ console.log("On Error Callback", error);
2033
+ });
2034
+
2035
+ button.onPaymentSuccessful(function(data) {
2036
+ console.log("Payment successful");
2037
+ console.log(data);
2038
+ });
2039
+
2040
+ button.onPaymentError(function(err) {
2041
+ console.log("Payment error");
2042
+ console.log(err);
2043
+ });
2044
+
2045
+ button.onPaymentInReview(function(data) {
2046
+ console.log("The payment is on fraud review");
2047
+ console.log(data);
2048
+ });
2049
+
2050
+ button.onClick(async (data) => {
2051
+ console.log("Button clicked", data);
2052
+
2053
+ const responseData = await fetch('https://your-server-url/initialize-wallet-charge');
2054
+ const parsedData = await responseData.json();
2055
+ return parsedData.resource.data.token;
2056
+ });
2057
+
2058
+ button.onCheckoutClose(() => {
2059
+ console.log("Checkout closed");
2060
+ });
2061
+
2062
+ button.load();
2063
+ </script>
2064
+ </html>
2065
+ ```
2066
+
2067
+ ## Open Wallet Buttons
2068
+ You can find description of all methods and parameters [here](https://www.npmjs.com/package/@paydock/client-sdk#open-wallet-buttons-simple-example)
2069
+
2070
+ Open Wallet Buttons provide a next-generation approach to integrating E-Wallets into your checkout with improved event handling and more granular control over wallet interactions.
2071
+
2072
+ Each wallet type has its own dedicated class with fully typed metadata:
2073
+ - [ApplePayOpenWalletButton](#ApplePayOpenWalletButton) - for Apple Pay integration
2074
+ - [GooglePayOpenWalletButton](#GooglePayOpenWalletButton) - for Google Pay integration
2075
+
2076
+ On `load()`, each button fetches the service configuration from PayDock and validates that the service type matches the expected wallet. If there is a mismatch (e.g. using an Apple Pay service ID with `GooglePayOpenWalletButton`), an error will be raised via the `onError` callback.
2077
+
2078
+ If available in your client environment, you will display a simple button that upon clicking it the user will follow the standard flow for the appropriate Wallet. If not available an event will be raised and no button will be displayed.
2079
+
2080
+ ## Apple Pay Open Wallet Button
2081
+
2082
+ ### Container
2083
+
2084
+ ```html
2085
+ <div id="widget"></div>
2086
+ ```
2087
+
2088
+ You must create a container for the Open Wallet Button. Inside this tag, the button will be initialized.
2089
+
2090
+ Before initializing the button, you must configure your Apple Pay wallet service through the PayDock dashboard and obtain the service ID that will be used to load the button configuration.
2091
+
2092
+ ### Initialization
2093
+
2094
+ ```javascript
2095
+ let button = new paydock.ApplePayOpenWalletButton(
2096
+ "#widget",
2097
+ publicKeyOrAccessToken,
2098
+ serviceId,
2099
+ {
2100
+ amount: 100,
2101
+ currency: "AUD",
2102
+ country: "AU",
2103
+ amount_label: "TOTAL",
2104
+ store_name: "My Store",
2105
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2106
+ }
2107
+ );
2108
+ button.load();
2109
+ ```
2110
+
2111
+ ```javascript
2112
+ // ES2015 | TypeScript
2113
+ import { ApplePayOpenWalletButton } from '@paydock/client-sdk';
2114
+
2115
+ var button = new ApplePayOpenWalletButton(
2116
+ '#widget',
2117
+ publicKeyOrAccessToken,
2118
+ serviceId,
2119
+ {
2120
+ amount: 100,
2121
+ currency: 'AUD',
2122
+ country: 'AU',
2123
+ amount_label: 'TOTAL',
2124
+ store_name: 'My Store',
2125
+ }
2126
+ );
2127
+ button.load();
2128
+ ```
2129
+
2130
+ ### Constructor Parameters
2131
+
2132
+ The ApplePayOpenWalletButton constructor accepts the following parameters:
2133
+
2134
+ 1. **selector** (string): CSS selector for the container element
2135
+ 2. **publicKeyOrAccessToken** (string): Your PayDock public key or access token
2136
+ 3. **serviceId** (string): The Apple Pay service ID configured in PayDock dashboard
2137
+ 4. **meta** (ApplePayOpenWalletMeta): Apple Pay-specific configuration object
2138
+
2139
+ > **Note:** Required meta fields (`amount`, `currency`, `country`, `amount_label`, `store_name`) are validated automatically by the `ApplePayOpenWalletButton` class. You do not need to specify them manually.
2140
+
2141
+ ### Setting environment
2142
+
2143
+ Current method can change environment. By default environment = sandbox.
2144
+ Bear in mind that you must set an environment before calling `button.load()`.
2145
+
2146
+ ```javascript
2147
+ button.setEnv('sandbox');
2148
+ ```
2149
+
2150
+ ### Full Apple Pay example
2151
+
2152
+ ```html
2153
+ <!DOCTYPE html>
2154
+ <html lang="en">
2155
+ <head>
2156
+ <meta charset="UTF-8">
2157
+ <title>Apple Pay with Open Wallets</title>
2158
+ </head>
2159
+ <body>
2160
+ <h2>Payment using PayDock Apple Pay Open Wallet Button!</h2>
2161
+ <div id="widget"></div>
2162
+ </body>
2163
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
2164
+ <script>
2165
+ let button = new paydock.ApplePayOpenWalletButton(
2166
+ "#widget",
2167
+ publicKeyOrAccessToken,
2168
+ serviceId,
2169
+ {
2170
+ amount: 100,
2171
+ currency: "AUD",
2172
+ country: "AU",
2173
+ amount_label: "TOTAL",
2174
+ store_name: "My Store",
2175
+ request_shipping: true,
2176
+ request_payer_name: true,
2177
+ request_payer_email: true,
2178
+ request_payer_phone: true,
2179
+ show_billing_address: true,
2180
+ style: {
2181
+ button_type: 'buy',
2182
+ button_style: 'black'
2183
+ },
2184
+ shipping_options: [
2185
+ {
2186
+ id: "standard",
2187
+ label: "Standard Shipping",
2188
+ detail: "Arrives in 5 to 7 days",
2189
+ amount: 5.00,
2190
+ date_components_range: {
2191
+ start_date_components: {
2192
+ years: 0,
2193
+ months: 0,
2194
+ days: 5,
2195
+ hours: 0,
2196
+ },
2197
+ end_date_components: {
2198
+ years: 0,
2199
+ months: 0,
2200
+ days: 7,
2201
+ hours: 0,
2202
+ }
2203
+ }
2204
+ },
2205
+ {
2206
+ id: "express",
2207
+ label: "Express Shipping",
2208
+ detail: "Arrives in 1 to 2 days",
2209
+ amount: 15.00,
2210
+ date_components_range: {
2211
+ start_date_components: {
2212
+ years: 0,
2213
+ months: 0,
2214
+ days: 1,
2215
+ hours: 0,
2216
+ },
2217
+ end_date_components: {
2218
+ years: 0,
2219
+ months: 0,
2220
+ days: 2,
2221
+ hours: 0,
2222
+ }
2223
+ }
2224
+ }
2225
+ ],
2226
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
2227
+ }
2228
+ );
2229
+
2230
+ button.setEnv('sandbox');
2231
+
2232
+ button.onUnavailable((data) => {
2233
+ console.log("Apple Pay not available:", data);
2234
+ // Show alternative payment methods
2235
+ });
2236
+
2237
+ button.onClick((data) => {
2238
+ console.log("Apple Pay button clicked");
2239
+ // Perform pre-payment validation
2240
+ });
2241
+
2242
+ button.onSuccess((data) => {
2243
+ console.log("Payment successful:", data);
2244
+ // Process the OTT token on your backend
2245
+ processPayment(data.token);
2246
+ });
2247
+
2248
+ button.onError((data) => {
2249
+ console.error("Payment error:", data);
2250
+ // Handle error appropriately
2251
+ });
2252
+
2253
+ button.onCancel((data) => {
2254
+ console.log("Payment cancelled");
2255
+ // Handle cancellation
2256
+ });
2257
+
2258
+ button.onShippingAddressChange(async (addressData) => {
2259
+ // Update shipping costs based on address
2260
+ const response = await updateShippingCosts(addressData);
2261
+ return {
2262
+ amount: response.newAmount,
2263
+ shipping_options: response.shippingOptions
2264
+ };
2265
+ });
2266
+
2267
+ button.onShippingOptionsChange(async (optionData) => {
2268
+ // Update total based on selected shipping option
2269
+ const response = await updateTotal(optionData);
2270
+ return {
2271
+ amount: response.newAmount
2272
+ };
2273
+ });
2274
+
2275
+ button.load();
2276
+
2277
+ async function updateShippingCosts(addressData) {
2278
+ // Your shipping calculation logic based on address
2279
+ const baseAmount = 100;
2280
+ const updatedShippingOptions = [
2281
+ {
2282
+ id: "updated-standard",
2283
+ label: "Updated Standard Shipping",
2284
+ detail: "Based on your location",
2285
+ amount: 8.00
2286
+ },
2287
+ {
2288
+ id: "updated-express",
2289
+ label: "Updated Express Shipping",
2290
+ detail: "Fast delivery to your area",
2291
+ amount: 18.00
2292
+ }
2293
+ ];
2294
+
2295
+ return {
2296
+ newAmount: baseAmount + updatedShippingOptions[0].amount,
2297
+ shippingOptions: updatedShippingOptions
2298
+ };
2299
+ }
2300
+
2301
+ async function updateTotal(optionData) {
2302
+ // Your total calculation logic
2303
+ const baseAmount = 100;
2304
+ const shippingAmount = optionData.amount || optionData.data?.amount;
2305
+ return {
2306
+ newAmount: baseAmount + shippingAmount
2307
+ };
2308
+ }
2309
+
2310
+ function processPayment(ottToken) {
2311
+ // Send OTT token to your backend for payment processing
2312
+ fetch('/api/process-payment', {
2313
+ method: 'POST',
2314
+ headers: { 'Content-Type': 'application/json' },
2315
+ body: JSON.stringify({ ott_token: ottToken })
2316
+ });
2317
+ }
2318
+ </script>
2319
+ </html>
2320
+ ```
2321
+
2322
+ ### Apple Pay with Shipping
2323
+
2324
+ For Apple Pay with shipping enabled:
2325
+ ```javascript
2326
+ let button = new paydock.ApplePayOpenWalletButton(
2327
+ "#widget",
2328
+ publicKeyOrAccessToken,
2329
+ serviceId,
2330
+ {
2331
+ amount: 100,
2332
+ currency: "AUD",
2333
+ country: "AU",
2334
+ amount_label: "TOTAL",
2335
+ store_name: "My Store",
2336
+ request_shipping: true,
2337
+ shipping_editing_mode: 'available',
2338
+ required_shipping_contact_fields: [
2339
+ 'postalAddress',
2340
+ 'name',
2341
+ 'phone',
2342
+ 'email',
2343
+ ],
2344
+ shipping_options: [
2345
+ {
2346
+ id: "standard",
2347
+ label: "Standard Shipping",
2348
+ detail: "5-7 business days",
2349
+ amount: 5.00
2350
+ },
2351
+ {
2352
+ id: "express",
2353
+ label: "Express Shipping",
2354
+ detail: "1-2 business days",
2355
+ amount: 15.00
2356
+ }
2357
+ ],
2358
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
2359
+ }
2360
+ );
2361
+ button.load();
2362
+ ```
2363
+
2364
+ When supporting shipping, the methods `onShippingAddressChange` and `onShippingOptionsChange` are required to update the shipping address and options.
2365
+
2366
+ ```javascript
2367
+ button.onShippingAddressChange(async function(data) {
2368
+ console.log("Shipping address has been updated", data);
2369
+ // Call your backend to recalculate shipping
2370
+ return {
2371
+ amount: newAmount,
2372
+ shipping_options: updatedShippingOptions
2373
+ };
2374
+ });
2375
+
2376
+ button.onShippingOptionsChange(async function(data) {
2377
+ console.log("Shipping option selected", data);
2378
+ // Update total based on selected shipping option
2379
+ return {
2380
+ amount: newTotalAmount
2381
+ };
2382
+ });
2383
+ ```
2384
+
2385
+ ### Supported Shipping Cases
2386
+
2387
+ #### Injected Shipping Address, non-editable by the customer
2388
+
2389
+ This is the case where the shipping address is injected by the merchant and is not editable by the customer. The customer can only select the shipping option.
2390
+
2391
+ The required meta parameters for this case are:
2392
+ - shipping_editing_mode: 'store_pickup'
2393
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2394
+
2395
+ ```javascript
2396
+ meta: {
2397
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2398
+ amount_label: 'TOTAL',
2399
+ country: 'AU',
2400
+ currency: 'AUD',
2401
+ amount: 10,
2402
+ shipping_editing_mode: 'store_pickup',
2403
+ required_shipping_contact_fields: [
2404
+ 'postalAddress',
2405
+ 'name',
2406
+ 'phone',
2407
+ 'email',
2408
+ ],
2409
+ shipping: {
2410
+ amount: 5,
2411
+ address_line1: "Address Line 1",
2412
+ address_city: "Test Locality",
2413
+ address_state: "NSW",
2414
+ address_country: "Australia",
2415
+ address_country_code: "AU",
2416
+ address_postcode: "3000",
2417
+ contact: {
2418
+ phone: "+61400245562",
2419
+ email: "test@example.com",
2420
+ first_name: "QA",
2421
+ last_name: "QA",
2422
+ },
2423
+ options: [
2424
+ {
2425
+ label: "Test 1",
2426
+ detail: "This is a test 1 shipping methods",
2427
+ amount: 10,
2428
+ id: "randomId1",
2429
+ }
2430
+ ],
2431
+ },
2432
+ }
2433
+ ```
2434
+
2435
+ #### Injected Shipping Address, editable by the customer
2436
+
2437
+ This is the case where the shipping address is injected by the merchant and is editable by the customer. The customer can edit the shipping address and select the shipping option.
2438
+
2439
+ The required meta parameters for this case are:
2440
+ - shipping_editing_mode: 'available'
2441
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2442
+
2443
+ ```javascript
2444
+ meta: {
2445
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2446
+ amount_label: 'TOTAL',
2447
+ country: 'AU',
2448
+ currency: 'AUD',
2449
+ amount: 10,
2450
+ shipping_editing_mode: 'available',
2451
+ required_shipping_contact_fields: [
2452
+ 'postalAddress',
2453
+ 'name',
2454
+ 'phone',
2455
+ 'email',
2456
+ ],
2457
+ shipping: {
2458
+ amount: 5,
2459
+ address_line1: "Address Line 1",
2460
+ address_city: "Test Locality",
2461
+ address_state: "NSW",
2462
+ address_country: "Australia",
2463
+ address_country_code: "AU",
2464
+ address_postcode: "3000",
2465
+ contact: {
2466
+ phone: "+61400245562",
2467
+ email: "test@example.com",
2468
+ first_name: "QA",
2469
+ last_name: "QA",
2470
+ },
2471
+ options: [
2472
+ {
2473
+ label: "Test 1",
2474
+ detail: "This is a test 1 shipping methods",
2475
+ amount: 10,
2476
+ id: "randomId1",
2477
+ }
2478
+ ],
2479
+ },
2480
+ }
2481
+ ```
2482
+
2483
+ #### Shipping address editable by the customer (no pre-filled address)
2484
+
2485
+ This is the case where the shipping address is not injected by the merchant and is editable by the customer. The customer can edit the shipping address and select the shipping option.
2486
+
2487
+ The required meta parameters for this case are:
2488
+ - shipping_editing_mode: 'available'
2489
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2490
+
2491
+ ```javascript
2492
+ meta: {
2493
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2494
+ amount_label: 'TOTAL',
2495
+ country: 'AU',
2496
+ currency: 'AUD',
2497
+ amount: 10,
2498
+ shipping_editing_mode: 'available',
2499
+ required_shipping_contact_fields: [
2500
+ 'postalAddress',
2501
+ 'name',
2502
+ 'phone',
2503
+ 'email',
2504
+ ],
2505
+ }
2506
+ ```
2507
+
2508
+ #### No shipping address
2509
+
2510
+ This is the case where no shipping address is required at all in the popup (e.g., digital goods, services, or virtual products, or Shipping Address collected separately by the merchant). The "Send to" UI field will not be shown in the Apple Pay sheet, it will be hidden.
2511
+
2512
+ **Important:**
2513
+ - No shipping address should be provided in the meta object.
2514
+ - Shipping address could be provided in the initial POST `/v1/charges/wallet` endpoint, if collected previously.
2515
+
2516
+ The required meta parameters for this case are:
2517
+ - `required_shipping_contact_fields`: Only include contact fields if needed (phone, email), but NOT `postalAddress`.
2518
+
2519
+ ```javascript
2520
+ meta: {
2521
+ amount_label: "TOTAL",
2522
+ country: "AU",
2523
+ currency: "AUD",
2524
+ amount: 10,
2525
+ shipping_editing_mode: "available",
2526
+ required_shipping_contact_fields: ["phone", "email"],
2527
+ apple_pay_capabilities: ["credentials_available", "credentials_status_unknown", "credentials_unavailable"]
2528
+ }
2529
+ ```
2530
+
2531
+ ## Google Pay Open Wallet Button
2532
+
2533
+ ### Initialization
2534
+
2535
+ ```javascript
2536
+ let button = new paydock.GooglePayOpenWalletButton(
2537
+ "#widget",
2538
+ publicKeyOrAccessToken,
2539
+ serviceId,
2540
+ {
2541
+ amount: 100,
2542
+ currency: "AUD",
2543
+ country: "AU",
2544
+ merchant_name: "Your Store",
2545
+ }
2546
+ );
2547
+ button.load();
2548
+ ```
2549
+
2550
+ ```javascript
2551
+ // ES2015 | TypeScript
2552
+ import { GooglePayOpenWalletButton } from '@paydock/client-sdk';
2553
+
2554
+ var button = new GooglePayOpenWalletButton(
2555
+ '#widget',
2556
+ publicKeyOrAccessToken,
2557
+ serviceId,
2558
+ {
2559
+ amount: 100,
2560
+ currency: 'AUD',
2561
+ country: 'AU',
2562
+ merchant_name: 'Your Store',
2563
+ }
2564
+ );
2565
+ button.load();
2566
+ ```
2567
+
2568
+ ### Constructor Parameters
2569
+
2570
+ The GooglePayOpenWalletButton constructor accepts the following parameters:
2571
+
2572
+ 1. **selector** (string): CSS selector for the container element
2573
+ 2. **publicKeyOrAccessToken** (string): Your PayDock public key or access token
2574
+ 3. **serviceId** (string): The Google Pay service ID configured in PayDock dashboard
2575
+ 4. **meta** (GooglePayOpenWalletMeta): Google Pay-specific configuration object
2576
+
2577
+ > **Note:** Required meta fields (`amount`, `currency`, `country`) are validated automatically by the `GooglePayOpenWalletButton` class. You do not need to specify them manually.
2578
+
2579
+ ### Full Google Pay Example
2580
+
2581
+ ```html
2582
+ <!DOCTYPE html>
2583
+ <html lang="en">
2584
+ <head>
2585
+ <meta charset="UTF-8">
2586
+ <title>Google Pay with Open Wallets</title>
2587
+ </head>
2588
+ <body>
2589
+ <h2>Payment using PayDock Google Pay Open Wallet Button!</h2>
2590
+ <div id="widget"></div>
2591
+ </body>
2592
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
2593
+ <script>
2594
+ let button = new paydock.GooglePayOpenWalletButton(
2595
+ "#widget",
2596
+ publicKeyOrAccessToken,
2597
+ serviceId,
2598
+ {
2599
+ amount: 100,
2600
+ currency: "AUD",
2601
+ country: "AU",
2602
+ amount_label: "Total",
2603
+ request_shipping: true,
2604
+ show_billing_address: true,
2605
+ merchant_name: 'Test Merchant',
2606
+ style: {
2607
+ button_type: 'buy',
2608
+ button_color: 'default',
2609
+ button_size_mode: 'fill'
2610
+ },
2611
+ shipping_options: [
2612
+ {
2613
+ id: "standard",
2614
+ label: "Standard Shipping",
2615
+ detail: "Arrives in 5 to 7 days",
2616
+ amount: 5.00,
2617
+ type: "ELECTRONIC"
2618
+ },
2619
+ {
2620
+ id: "express",
2621
+ label: "Express Shipping",
2622
+ detail: "Arrives in 1 to 2 days",
2623
+ amount: 15.00,
2624
+ type: "PICKUP"
2625
+ }
2626
+ ]
2627
+ }
2628
+ );
2629
+
2630
+ button.setEnv('sandbox');
2631
+
2632
+ // Required handlers
2633
+ button.onSuccess((data) => {
2634
+ console.log("Payment successful:", data);
2635
+ processPayment(data.token);
2636
+ });
2637
+
2638
+ button.onShippingAddressChange(async (addressData) => {
2639
+ const response = await updateShippingCosts(addressData);
2640
+ return {
2641
+ amount: response.newAmount,
2642
+ shipping_options: response.shippingOptions
2643
+ };
2644
+ });
2645
+
2646
+ button.onShippingOptionsChange(async (optionData) => {
2647
+ const response = await updateTotal(optionData);
2648
+ return {
2649
+ amount: response.newAmount
2650
+ };
2651
+ });
2652
+
2653
+ // Optional handlers
2654
+ button.onUnavailable((data) => {
2655
+ console.log("Google Pay not available:", data);
2656
+ // Show alternative payment methods
2657
+ });
2658
+
2659
+ button.onError((data) => {
2660
+ console.error("Payment error:", data);
2661
+ // Handle error appropriately
2662
+ });
2663
+
2664
+ button.onCancel((data) => {
2665
+ console.log("Payment cancelled");
2666
+ // Handle cancellation
2667
+ });
2668
+
2669
+ button.onClick((data) => {
2670
+ console.log("Google Pay button clicked");
2671
+ // Perform pre-payment validation
2672
+ });
2673
+
2674
+ button.load();
2675
+
2676
+ // Helper functions
2677
+ async function updateShippingCosts(addressData) {
2678
+ const baseAmount = 100;
2679
+ const updatedShippingOptions = [
2680
+ {
2681
+ id: "updated-standard",
2682
+ label: "Updated Standard Shipping",
2683
+ detail: "Based on your location",
2684
+ amount: 8.00,
2685
+ type: "ELECTRONIC"
2686
+ },
2687
+ {
2688
+ id: "updated-express",
2689
+ label: "Updated Express Shipping",
2690
+ detail: "Fast delivery to your area",
2691
+ amount: 18.00,
2692
+ type: "PICKUP"
2693
+ }
2694
+ ];
2695
+
2696
+ return {
2697
+ newAmount: baseAmount + updatedShippingOptions[0].amount,
2698
+ shippingOptions: updatedShippingOptions
2699
+ };
2700
+ }
2701
+
2702
+ async function updateTotal(optionData) {
2703
+ const baseAmount = 100;
2704
+ const shippingAmount = optionData.amount || optionData.data?.amount;
2705
+ return {
2706
+ newAmount: baseAmount + shippingAmount
2707
+ };
2708
+ }
2709
+
2710
+ function processPayment(ottToken) {
2711
+ fetch('/api/process-payment', {
2712
+ method: 'POST',
2713
+ headers: { 'Content-Type': 'application/json' },
2714
+ body: JSON.stringify({ ott_token: ottToken })
2715
+ });
2716
+ }
2717
+ </script>
2718
+ </html>
2719
+ ```
2720
+
2721
+ ## Common API
2722
+
2723
+ Both `ApplePayOpenWalletButton` and `GooglePayOpenWalletButton` share the same event handler API inherited from the base class.
2724
+
2725
+ ### Checking for button availability
2726
+
2727
+ If the customer's browser is not supported, or the customer does not have any card added to their wallet, the button will not load. In this case the callback onUnavailable() will be called. You can define the behavior of this function before loading the button.
2728
+
2729
+ ```javascript
2730
+ button.onUnavailable((data) => console.log("No wallet button available", data));
2731
+ ```
2732
+
2733
+ ### Service type validation
2734
+
2735
+ Each button validates that the service configuration matches its expected wallet type. If you use an Apple Pay service ID with `GooglePayOpenWalletButton` (or vice versa), an error will be emitted via `onError`:
2736
+
2737
+ ```javascript
2738
+ // This will raise an error if the service ID does not correspond to a Google Pay service
2739
+ let button = new paydock.GooglePayOpenWalletButton(
2740
+ "#widget",
2741
+ publicKeyOrAccessToken,
2742
+ applePayServiceId, // Wrong! This is an Apple Pay service ID
2743
+ meta
2744
+ );
2745
+
2746
+ button.onError((data) => {
2747
+ // Error: Service configuration type 'ApplePay' does not match expected wallet type 'google'.
2748
+ console.error(data.error.message);
2749
+ });
2750
+
2751
+ button.load();
2752
+ ```
2753
+
2754
+ ### Performing actions when the wallet button is clicked
2755
+
2756
+ You can perform validations or actions when the user clicks on the wallet button. The callback supports both synchronous and asynchronous operations using the `attachResult` method.
2757
+
2758
+ ```javascript
2759
+ // Synchronous example
2760
+ button.onClick((data) => {
2761
+ console.log("Perform actions on button click");
2762
+ // Perform validation logic
2763
+ // Optionally use attachResult to control flow
2764
+ data.attachResult(true); // Continue with payment
2765
+ // data.attachResult(false); // Halt payment
2766
+ });
2767
+
2768
+ // Asynchronous example
2769
+ button.onClick((data) => {
2770
+ // Attach a Promise to control the wallet flow
2771
+ data.attachResult(
2772
+ fetch('/api/validate-order')
2773
+ .then(response => response.json())
2774
+ .then(result => {
2775
+ if (!result.valid) {
2776
+ throw new Error('Order validation failed');
2777
+ }
2778
+ return result;
2779
+ })
2780
+ );
2781
+ });
2782
+ ```
2783
+
2784
+ ### Handling successful OTT creation
2785
+
2786
+ When the One Time Token (OTT) is successfully created, the onSuccess callback will be called with the token data. **This callback is required** - if no handler is provided, an error will be thrown.
2787
+
2788
+ ```javascript
2789
+ button.onSuccess((data) => {
2790
+ console.log("OTT created successfully:", data.token);
2791
+ console.log("Amount:", data.amount);
2792
+ console.log("Shipping:", data.shipping);
2793
+ console.log("Billing:", data.billing);
2794
+
2795
+ // Use the OTT token to complete payment on your backend
2796
+ fetch('/api/process-payment', {
2797
+ method: 'POST',
2798
+ headers: { 'Content-Type': 'application/json' },
2799
+ body: JSON.stringify({ ott_token: data.token })
2800
+ });
2801
+ });
2802
+ ```
2803
+
2804
+ **Important**: The `onSuccess` event handler is mandatory. Not providing one will result in an error.
2805
+
2806
+ ### Updating meta after initialization
2807
+
2808
+ If the screen where the button is rendered allows for cart/amount changes, call `setMeta` method to update the meta information. The `setMeta` method is fully typed for each wallet:
2809
+
2810
+ ```javascript
2811
+ // For Apple Pay - accepts ApplePayOpenWalletMeta
2812
+ applePayButton.setMeta({ ...meta, amount: 29.99, amount_label: 'NEW TOTAL' });
2813
+
2814
+ // For Google Pay - accepts GooglePayOpenWalletMeta
2815
+ googlePayButton.setMeta({ ...meta, amount: 29.99, merchant_name: 'Updated Store' });
2816
+ ```
2817
+
2818
+ ### Handling errors
2819
+
2820
+ Register a callback function to handle errors that occur during wallet operations, including service type mismatches.
2821
+
2822
+ ```javascript
2823
+ button.onError((data) => {
2824
+ console.error("Open Wallet error:", data.error);
2825
+ console.log("Error context:", data.context);
2826
+
2827
+ // Show user-friendly error message
2828
+ showErrorMessage("Payment initialization failed. Please try again.");
2829
+ });
2830
+ ```
2831
+
2832
+ ### Handling checkout cancellation
2833
+
2834
+ When the user cancels or closes the wallet payment interface, you can perform cleanup operations.
2835
+
2836
+ ```javascript
2837
+ button.onCancel((data) => {
2838
+ console.log("Wallet checkout cancelled", data);
2839
+
2840
+ // Perform cleanup or redirect user
2841
+ window.location.href = '/checkout';
2842
+ });
2843
+ ```
2844
+
2845
+ ### Cleaning up
2846
+
2847
+ Remove the wallet button from the DOM when it is no longer needed:
2848
+
2849
+ ```javascript
2850
+ button.destroy();
2851
+ ```
2852
+
2853
+ ### Events
2854
+ The above events can be used in a more generic way via the `eventEmitter.subscribe` method internally, but the recommended approach is to use the dedicated event handler methods provided by the button classes.
2855
+
2856
+ **Available Event Handler Methods:**
2857
+ - `onClick(handler)` - Button click events (supports attachResult for flow control)
2858
+ - `onSuccess(handler)` - **Required** - OTT creation success events
2859
+ - `onUnavailable(handler)` - Wallet unavailable events (supports Promise pattern)
2860
+ - `onError(handler)` - Error events (supports Promise pattern)
2861
+ - `onCancel(handler)` - Checkout cancellation events (supports Promise pattern)
2862
+ - `onLoaded(handler)` - Button loaded/rendered events
2863
+ - `onShippingAddressChange(handler)` - **Required for shipping** - Address change events
2864
+ - `onShippingOptionsChange(handler)` - **Required for shipping options** - Option change events
2865
+
2866
+ **Event Handler Patterns:**
2867
+
2868
+ ```javascript
2869
+ // Required handlers (will throw error if not provided)
2870
+ button.onSuccess(handler); // Always required
2871
+ button.onShippingAddressChange(handler); // Required when shipping enabled
2872
+ button.onShippingOptionsChange(handler); // Required when shipping options provided
2873
+
2874
+ // Optional handlers with Promise support
2875
+ button.onUnavailable(handler); // or await button.onUnavailable()
2876
+ button.onError(handler); // or await button.onError()
2877
+ button.onCancel(handler); // or await button.onCancel()
2878
+
2879
+ // Click handler with flow control
2880
+ button.onClick(handler); // Use data.attachResult() for async operations
2881
+
2882
+ // Loaded handler
2883
+ button.onLoaded(handler); // Notified when button renders
2884
+ ```
2885
+
2886
+ ### Apple Pay-Specific Meta Properties
2887
+
2888
+ A full description of the [ApplePayOpenWalletMeta](#ApplePayOpenWalletMeta) properties:
2889
+
2890
+ **Required:**
2891
+ - `amount`: The payment amount (number)
2892
+ - `currency`: The currency code (string, e.g., "AUD")
2893
+ - `country`: The country code (string, e.g., "AU")
2894
+ - `amount_label`: Label for the total amount (string)
2895
+ - `store_name`: Merchant store name (string)
2896
+
2897
+ **Optional:**
2898
+ - `request_shipping?: boolean`: Enable shipping address collection
2899
+ - `shipping_options?: IApplePayShippingOption[]`: Array of shipping options
2900
+ - `show_billing_address?: boolean`: Show billing address fields
2901
+ - `apple_pay_capabilities?: string[]`: Device capabilities
2902
+ - `merchant_capabilities?: string[]`: Merchant capabilities
2903
+ - `supported_networks?: string[]`: Supported payment networks
2904
+ - `required_billing_contact_fields?: string[]`: Required billing contact fields
2905
+ - `required_shipping_contact_fields?: string[]`: Required shipping contact fields
2906
+ - `supported_countries?: string[]`: Supported countries
2907
+ - `shipping_editing_mode?: 'available' | 'store_pickup'`: Shipping address editing mode
2908
+ - `style?: { button_type?: ApplePayButtonType, button_style?: ApplePayButtonStyle }`: Button styling
2909
+
2910
+ ### Google Pay-Specific Meta Properties
2911
+
2912
+ A full description of the [GooglePayOpenWalletMeta](#GooglePayOpenWalletMeta) properties:
2913
+
2914
+ **Required:**
2915
+ - `amount`: The payment amount (number)
2916
+ - `currency`: The currency code (string, e.g., "AUD")
2917
+ - `country`: The country code (string, e.g., "AU")
2918
+
2919
+ **Optional:**
2920
+ - `amount_label?: string`: Label for the total amount
2921
+ - `merchant_name?: string`: Display name for the merchant
2922
+ - `request_shipping?: boolean`: Enable shipping address collection
2923
+ - `shipping_options?: IGooglePayShippingOption[]`: Array of shipping options
2924
+ - `show_billing_address?: boolean`: Show billing address fields
2925
+ - `card_config?: GooglePayCardConfig`: Card configuration (auth methods, networks, tokenization)
2926
+ - `style?: { button_type?: GooglePayButtonType, button_color?: GooglePayButtonColor, button_size_mode?: GooglePayButtonSizeMode }`: Button styling
2927
+
2928
+ ### Shipping Options Format
2929
+ ```javascript
2930
+ shipping_options: [
2931
+ {
2932
+ id: "option_id", // Unique identifier (string)
2933
+ label: "Option Name", // Display name (string)
2934
+ detail: "Description", // Optional description (string)
2935
+ amount: 10.00, // Shipping cost as number
2936
+ date_components_range: { // Optional: delivery date range (Apple Pay only)
2937
+ start_date_components: {
2938
+ years: 0,
2939
+ months: 0,
2940
+ days: 5,
2941
+ hours: 0,
2942
+ },
2943
+ end_date_components: {
2944
+ years: 0,
2945
+ months: 0,
2946
+ days: 10,
2947
+ hours: 0,
2948
+ }
2949
+ }
2950
+ }
2951
+ ]
2952
+ ```
2953
+
2954
+ **Important**:
2955
+ - `amount` should be a **number**, not a string
2956
+ - `date_components_range` is optional but provides delivery estimates (Apple Pay only)
2957
+ - Updated shipping options returned from event handlers don't require `date_components_range`
2958
+
2959
+ ### Environment Setup
2960
+ ```javascript
2961
+ // Always set environment before loading
2962
+ button.setEnv('sandbox');
2963
+ button.load();
2964
+ ```
2965
+
2966
+ ### Error Handling Best Practices
2967
+ ```javascript
2968
+ button.onError(function(data) {
2969
+ console.error('Full error object:', data);
2970
+
2971
+ // Check different error properties
2972
+ const errorMessage = data.error?.message ||
2973
+ data.message ||
2974
+ 'Unknown error occurred';
2975
+
2976
+ // Handle different error types
2977
+ if (data.context?.operation === 'wallet_operation') {
2978
+ // Handle wallet-specific errors
2979
+ showWalletError(errorMessage);
2980
+ } else {
2981
+ // Handle general errors
2982
+ showGeneralError(errorMessage);
2983
+ }
2984
+ });
2985
+ ```
2986
+
1314
2987
  # Click To Pay
1315
2988
 
1316
2989
  ## Overview