@paydock/client-sdk 1.139.0 → 1.140.1

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 +2543 -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 +523 -822
  71. package/docs/open-wallet-buttons.md +1652 -0
  72. package/package.json +1 -1
  73. package/slate.md +1643 -0
package/slate.md CHANGED
@@ -1311,6 +1311,1649 @@ 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
+ });
2235
+
2236
+ button.onClick(() => {
2237
+ console.log("Apple Pay button clicked");
2238
+ });
2239
+
2240
+ button.onSuccess(({ data }) => {
2241
+ console.log("Payment successful:", data);
2242
+ processPayment(data.token);
2243
+ });
2244
+
2245
+ button.onError(({ data }) => {
2246
+ console.error("Payment error:", data);
2247
+ });
2248
+
2249
+ button.onCancel(() => {
2250
+ console.log("Payment cancelled");
2251
+ });
2252
+
2253
+ button.onShippingAddressChange(async ({ data }) => {
2254
+ const response = await updateShippingCosts(data);
2255
+ return {
2256
+ amount: response.newAmount,
2257
+ shipping_options: response.shippingOptions
2258
+ };
2259
+ });
2260
+
2261
+ button.onShippingOptionsChange(async ({ data }) => {
2262
+ const response = await updateTotal(data);
2263
+ return {
2264
+ amount: response.newAmount
2265
+ };
2266
+ });
2267
+
2268
+ button.load();
2269
+
2270
+ async function updateShippingCosts(addressData) {
2271
+ // Your shipping calculation logic based on address
2272
+ const baseAmount = 100;
2273
+ const updatedShippingOptions = [
2274
+ {
2275
+ id: "updated-standard",
2276
+ label: "Updated Standard Shipping",
2277
+ detail: "Based on your location",
2278
+ amount: 8.00
2279
+ },
2280
+ {
2281
+ id: "updated-express",
2282
+ label: "Updated Express Shipping",
2283
+ detail: "Fast delivery to your area",
2284
+ amount: 18.00
2285
+ }
2286
+ ];
2287
+
2288
+ return {
2289
+ newAmount: baseAmount + updatedShippingOptions[0].amount,
2290
+ shippingOptions: updatedShippingOptions
2291
+ };
2292
+ }
2293
+
2294
+ async function updateTotal(shippingOption) {
2295
+ const baseAmount = 100;
2296
+ const shippingAmount = shippingOption.amount;
2297
+ return {
2298
+ newAmount: baseAmount + shippingAmount
2299
+ };
2300
+ }
2301
+
2302
+ function processPayment(ottToken) {
2303
+ fetch('/api/process-payment', {
2304
+ method: 'POST',
2305
+ headers: { 'Content-Type': 'application/json' },
2306
+ body: JSON.stringify({ ott_token: ottToken })
2307
+ });
2308
+ }
2309
+ </script>
2310
+ </html>
2311
+ ```
2312
+
2313
+ ### Apple Pay with Shipping
2314
+
2315
+ For Apple Pay with shipping enabled:
2316
+ ```javascript
2317
+ let button = new paydock.ApplePayOpenWalletButton(
2318
+ "#widget",
2319
+ publicKeyOrAccessToken,
2320
+ serviceId,
2321
+ {
2322
+ amount: 100,
2323
+ currency: "AUD",
2324
+ country: "AU",
2325
+ amount_label: "TOTAL",
2326
+ store_name: "My Store",
2327
+ request_shipping: true,
2328
+ shipping_editing_mode: 'available',
2329
+ required_shipping_contact_fields: [
2330
+ 'postalAddress',
2331
+ 'name',
2332
+ 'phone',
2333
+ 'email',
2334
+ ],
2335
+ shipping_options: [
2336
+ {
2337
+ id: "standard",
2338
+ label: "Standard Shipping",
2339
+ detail: "5-7 business days",
2340
+ amount: 5.00
2341
+ },
2342
+ {
2343
+ id: "express",
2344
+ label: "Express Shipping",
2345
+ detail: "1-2 business days",
2346
+ amount: 15.00
2347
+ }
2348
+ ],
2349
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
2350
+ }
2351
+ );
2352
+ button.load();
2353
+ ```
2354
+
2355
+ When supporting shipping, registering `onShippingAddressChange` and `onShippingOptionsChange` handlers lets you recalculate totals and update shipping options dynamically. If no handler is registered (or the handler throws), the SDK auto-accepts with the current amount and options.
2356
+
2357
+ ```javascript
2358
+ button.onShippingAddressChange(async function({ data }) {
2359
+ console.log("Shipping address has been updated", data);
2360
+ return {
2361
+ amount: newAmount,
2362
+ shipping_options: updatedShippingOptions
2363
+ };
2364
+ });
2365
+
2366
+ button.onShippingOptionsChange(async function({ data }) {
2367
+ console.log("Shipping option selected", data);
2368
+ return {
2369
+ amount: newTotalAmount
2370
+ };
2371
+ });
2372
+ ```
2373
+
2374
+ ### Supported Shipping Cases
2375
+
2376
+ #### Injected Shipping Address, non-editable by the customer
2377
+
2378
+ 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.
2379
+
2380
+ The required meta parameters for this case are:
2381
+ - shipping_editing_mode: 'store_pickup'
2382
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2383
+
2384
+ ```javascript
2385
+ meta: {
2386
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2387
+ amount_label: 'TOTAL',
2388
+ country: 'AU',
2389
+ currency: 'AUD',
2390
+ amount: 10,
2391
+ shipping_editing_mode: 'store_pickup',
2392
+ required_shipping_contact_fields: [
2393
+ 'postalAddress',
2394
+ 'name',
2395
+ 'phone',
2396
+ 'email',
2397
+ ],
2398
+ shipping: {
2399
+ amount: 5,
2400
+ address_line1: "Address Line 1",
2401
+ address_city: "Test Locality",
2402
+ address_state: "NSW",
2403
+ address_country: "Australia",
2404
+ address_country_code: "AU",
2405
+ address_postcode: "3000",
2406
+ contact: {
2407
+ phone: "+61400245562",
2408
+ email: "test@example.com",
2409
+ first_name: "QA",
2410
+ last_name: "QA",
2411
+ },
2412
+ options: [
2413
+ {
2414
+ label: "Test 1",
2415
+ detail: "This is a test 1 shipping methods",
2416
+ amount: 10,
2417
+ id: "randomId1",
2418
+ }
2419
+ ],
2420
+ },
2421
+ }
2422
+ ```
2423
+
2424
+ #### Injected Shipping Address, editable by the customer
2425
+
2426
+ 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.
2427
+
2428
+ The required meta parameters for this case are:
2429
+ - shipping_editing_mode: 'available'
2430
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2431
+
2432
+ ```javascript
2433
+ meta: {
2434
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2435
+ amount_label: 'TOTAL',
2436
+ country: 'AU',
2437
+ currency: 'AUD',
2438
+ amount: 10,
2439
+ shipping_editing_mode: 'available',
2440
+ required_shipping_contact_fields: [
2441
+ 'postalAddress',
2442
+ 'name',
2443
+ 'phone',
2444
+ 'email',
2445
+ ],
2446
+ shipping: {
2447
+ amount: 5,
2448
+ address_line1: "Address Line 1",
2449
+ address_city: "Test Locality",
2450
+ address_state: "NSW",
2451
+ address_country: "Australia",
2452
+ address_country_code: "AU",
2453
+ address_postcode: "3000",
2454
+ contact: {
2455
+ phone: "+61400245562",
2456
+ email: "test@example.com",
2457
+ first_name: "QA",
2458
+ last_name: "QA",
2459
+ },
2460
+ options: [
2461
+ {
2462
+ label: "Test 1",
2463
+ detail: "This is a test 1 shipping methods",
2464
+ amount: 10,
2465
+ id: "randomId1",
2466
+ }
2467
+ ],
2468
+ },
2469
+ }
2470
+ ```
2471
+
2472
+ #### Shipping address editable by the customer (no pre-filled address)
2473
+
2474
+ 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.
2475
+
2476
+ The required meta parameters for this case are:
2477
+ - shipping_editing_mode: 'available'
2478
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
2479
+
2480
+ ```javascript
2481
+ meta: {
2482
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
2483
+ amount_label: 'TOTAL',
2484
+ country: 'AU',
2485
+ currency: 'AUD',
2486
+ amount: 10,
2487
+ shipping_editing_mode: 'available',
2488
+ required_shipping_contact_fields: [
2489
+ 'postalAddress',
2490
+ 'name',
2491
+ 'phone',
2492
+ 'email',
2493
+ ],
2494
+ }
2495
+ ```
2496
+
2497
+ #### No shipping address
2498
+
2499
+ 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.
2500
+
2501
+ **Important:**
2502
+ - No shipping address should be provided in the meta object.
2503
+ - Shipping address could be provided in the initial POST `/v1/charges/wallet` endpoint, if collected previously.
2504
+
2505
+ The required meta parameters for this case are:
2506
+ - `required_shipping_contact_fields`: Only include contact fields if needed (phone, email), but NOT `postalAddress`.
2507
+
2508
+ ```javascript
2509
+ meta: {
2510
+ amount_label: "TOTAL",
2511
+ country: "AU",
2512
+ currency: "AUD",
2513
+ amount: 10,
2514
+ shipping_editing_mode: "available",
2515
+ required_shipping_contact_fields: ["phone", "email"],
2516
+ apple_pay_capabilities: ["credentials_available", "credentials_status_unknown", "credentials_unavailable"]
2517
+ }
2518
+ ```
2519
+
2520
+ ## Google Pay Open Wallet Button
2521
+
2522
+ ### Initialization
2523
+
2524
+ ```javascript
2525
+ let button = new paydock.GooglePayOpenWalletButton(
2526
+ "#widget",
2527
+ publicKeyOrAccessToken,
2528
+ serviceId,
2529
+ {
2530
+ amount: 100,
2531
+ currency: "AUD",
2532
+ country: "AU",
2533
+ merchant_name: "Your Store",
2534
+ }
2535
+ );
2536
+ button.load();
2537
+ ```
2538
+
2539
+ ```javascript
2540
+ // ES2015 | TypeScript
2541
+ import { GooglePayOpenWalletButton } from '@paydock/client-sdk';
2542
+
2543
+ var button = new GooglePayOpenWalletButton(
2544
+ '#widget',
2545
+ publicKeyOrAccessToken,
2546
+ serviceId,
2547
+ {
2548
+ amount: 100,
2549
+ currency: 'AUD',
2550
+ country: 'AU',
2551
+ merchant_name: 'Your Store',
2552
+ }
2553
+ );
2554
+ button.load();
2555
+ ```
2556
+
2557
+ ### Constructor Parameters
2558
+
2559
+ The GooglePayOpenWalletButton constructor accepts the following parameters:
2560
+
2561
+ 1. **selector** (string): CSS selector for the container element
2562
+ 2. **publicKeyOrAccessToken** (string): Your PayDock public key or access token
2563
+ 3. **serviceId** (string): The Google Pay service ID configured in PayDock dashboard
2564
+ 4. **meta** (GooglePayOpenWalletMeta): Google Pay-specific configuration object
2565
+
2566
+ > **Note:** Required meta fields (`amount`, `currency`, `country`) are validated automatically by the `GooglePayOpenWalletButton` class. You do not need to specify them manually.
2567
+
2568
+ ### Full Google Pay Example
2569
+
2570
+ ```html
2571
+ <!DOCTYPE html>
2572
+ <html lang="en">
2573
+ <head>
2574
+ <meta charset="UTF-8">
2575
+ <title>Google Pay with Open Wallets</title>
2576
+ </head>
2577
+ <body>
2578
+ <h2>Payment using PayDock Google Pay Open Wallet Button!</h2>
2579
+ <div id="widget"></div>
2580
+ </body>
2581
+ <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
2582
+ <script>
2583
+ let button = new paydock.GooglePayOpenWalletButton(
2584
+ "#widget",
2585
+ publicKeyOrAccessToken,
2586
+ serviceId,
2587
+ {
2588
+ amount: 100,
2589
+ currency: "AUD",
2590
+ country: "AU",
2591
+ amount_label: "Total",
2592
+ request_shipping: true,
2593
+ show_billing_address: true,
2594
+ merchant_name: 'Test Merchant',
2595
+ style: {
2596
+ button_type: 'buy',
2597
+ button_color: 'default',
2598
+ button_size_mode: 'fill'
2599
+ },
2600
+ shipping_options: [
2601
+ {
2602
+ id: "standard",
2603
+ label: "Standard Shipping",
2604
+ detail: "Arrives in 5 to 7 days",
2605
+ amount: 5.00,
2606
+ type: "ELECTRONIC"
2607
+ },
2608
+ {
2609
+ id: "express",
2610
+ label: "Express Shipping",
2611
+ detail: "Arrives in 1 to 2 days",
2612
+ amount: 15.00,
2613
+ type: "PICKUP"
2614
+ }
2615
+ ]
2616
+ }
2617
+ );
2618
+
2619
+ button.setEnv('sandbox');
2620
+
2621
+ button.onSuccess(({ data }) => {
2622
+ console.log("Payment successful:", data);
2623
+ processPayment(data.token);
2624
+ });
2625
+
2626
+ button.onShippingAddressChange(async ({ data }) => {
2627
+ const response = await updateShippingCosts(data);
2628
+ return {
2629
+ amount: response.newAmount,
2630
+ shipping_options: response.shippingOptions
2631
+ };
2632
+ });
2633
+
2634
+ button.onShippingOptionsChange(async ({ data }) => {
2635
+ const response = await updateTotal(data);
2636
+ return {
2637
+ amount: response.newAmount
2638
+ };
2639
+ });
2640
+
2641
+ button.onUnavailable(({ data }) => {
2642
+ console.log("Google Pay not available:", data);
2643
+ });
2644
+
2645
+ button.onError(({ data }) => {
2646
+ console.error("Payment error:", data);
2647
+ });
2648
+
2649
+ button.onCancel(() => {
2650
+ console.log("Payment cancelled");
2651
+ });
2652
+
2653
+ button.onClick(() => {
2654
+ console.log("Google Pay button clicked");
2655
+ });
2656
+
2657
+ button.load();
2658
+
2659
+ // Helper functions
2660
+ async function updateShippingCosts(addressData) {
2661
+ const baseAmount = 100;
2662
+ const updatedShippingOptions = [
2663
+ {
2664
+ id: "updated-standard",
2665
+ label: "Updated Standard Shipping",
2666
+ detail: "Based on your location",
2667
+ amount: 8.00,
2668
+ type: "ELECTRONIC"
2669
+ },
2670
+ {
2671
+ id: "updated-express",
2672
+ label: "Updated Express Shipping",
2673
+ detail: "Fast delivery to your area",
2674
+ amount: 18.00,
2675
+ type: "PICKUP"
2676
+ }
2677
+ ];
2678
+
2679
+ return {
2680
+ newAmount: baseAmount + updatedShippingOptions[0].amount,
2681
+ shippingOptions: updatedShippingOptions
2682
+ };
2683
+ }
2684
+
2685
+ async function updateTotal(shippingOption) {
2686
+ const baseAmount = 100;
2687
+ const shippingAmount = shippingOption.amount;
2688
+ return {
2689
+ newAmount: baseAmount + shippingAmount
2690
+ };
2691
+ }
2692
+
2693
+ function processPayment(ottToken) {
2694
+ fetch('/api/process-payment', {
2695
+ method: 'POST',
2696
+ headers: { 'Content-Type': 'application/json' },
2697
+ body: JSON.stringify({ ott_token: ottToken })
2698
+ });
2699
+ }
2700
+ </script>
2701
+ </html>
2702
+ ```
2703
+
2704
+ ## Common API
2705
+
2706
+ Both `ApplePayOpenWalletButton` and `GooglePayOpenWalletButton` share the same event handler API inherited from the base class.
2707
+
2708
+ ### Checking for button availability
2709
+
2710
+ 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.
2711
+
2712
+ ```javascript
2713
+ button.onUnavailable(({ data }) => console.log("No wallet button available", data));
2714
+ ```
2715
+
2716
+ ### Service type validation
2717
+
2718
+ 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`:
2719
+
2720
+ ```javascript
2721
+ // This will raise an error if the service ID does not correspond to a Google Pay service
2722
+ let button = new paydock.GooglePayOpenWalletButton(
2723
+ "#widget",
2724
+ publicKeyOrAccessToken,
2725
+ applePayServiceId, // Wrong! This is an Apple Pay service ID
2726
+ meta
2727
+ );
2728
+
2729
+ button.onError(({ data }) => {
2730
+ // Error: Service configuration type 'ApplePay' does not match expected wallet type 'google'.
2731
+ console.error(data.error.message);
2732
+ });
2733
+
2734
+ button.load();
2735
+ ```
2736
+
2737
+ ### Performing actions when the wallet button is clicked
2738
+
2739
+ You can perform validations or actions when the user clicks on the wallet button. The callback supports both synchronous and asynchronous operations using its return value: return `false` to abort, return a `Promise` to defer the wallet sheet, or throw an error to abort.
2740
+
2741
+ ```javascript
2742
+ // Synchronous — continue normally
2743
+ button.onClick(() => {
2744
+ console.log("Perform actions on button click");
2745
+ });
2746
+
2747
+ // Synchronous — return false to abort the payment flow
2748
+ button.onClick(() => {
2749
+ if (!isOrderValid()) return false;
2750
+ });
2751
+
2752
+ // Asynchronous — defer the wallet sheet until the promise resolves
2753
+ button.onClick(async () => {
2754
+ const response = await fetch('/api/validate-order');
2755
+ const result = await response.json();
2756
+ if (!result.valid) {
2757
+ throw new Error('Order validation failed');
2758
+ }
2759
+ });
2760
+ ```
2761
+
2762
+ ### Handling successful OTT creation
2763
+
2764
+ 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.
2765
+
2766
+ ```javascript
2767
+ button.onSuccess(({ data }) => {
2768
+ console.log("OTT created successfully:", data.token);
2769
+ console.log("Amount:", data.amount);
2770
+ console.log("Shipping:", data.shipping);
2771
+ console.log("Billing:", data.billing);
2772
+
2773
+ fetch('/api/process-payment', {
2774
+ method: 'POST',
2775
+ headers: { 'Content-Type': 'application/json' },
2776
+ body: JSON.stringify({ ott_token: data.token })
2777
+ });
2778
+ });
2779
+ ```
2780
+
2781
+ **Important**: The `onSuccess` event handler is mandatory. Not providing one will result in an error.
2782
+
2783
+ ### Updating meta after initialization
2784
+
2785
+ 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:
2786
+
2787
+ ```javascript
2788
+ // For Apple Pay - accepts ApplePayOpenWalletMeta
2789
+ applePayButton.setMeta({ ...meta, amount: 29.99, amount_label: 'NEW TOTAL' });
2790
+
2791
+ // For Google Pay - accepts GooglePayOpenWalletMeta
2792
+ googlePayButton.setMeta({ ...meta, amount: 29.99, merchant_name: 'Updated Store' });
2793
+ ```
2794
+
2795
+ ### Handling errors
2796
+
2797
+ Register a callback function to handle errors that occur during wallet operations, including service type mismatches.
2798
+
2799
+ ```javascript
2800
+ button.onError(({ data }) => {
2801
+ console.error("Open Wallet error:", data.error);
2802
+ console.log("Error context:", data.context);
2803
+
2804
+ showErrorMessage("Payment initialization failed. Please try again.");
2805
+ });
2806
+ ```
2807
+
2808
+ ### Handling checkout cancellation
2809
+
2810
+ When the user cancels or closes the wallet payment interface, you can perform cleanup operations.
2811
+
2812
+ ```javascript
2813
+ button.onCancel(() => {
2814
+ console.log("Wallet checkout cancelled");
2815
+ window.location.href = '/checkout';
2816
+ });
2817
+ ```
2818
+
2819
+ ### Cleaning up
2820
+
2821
+ Remove the wallet button from the DOM when it is no longer needed:
2822
+
2823
+ ```javascript
2824
+ button.destroy();
2825
+ ```
2826
+
2827
+ ### Events
2828
+ 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.
2829
+
2830
+ **Available Event Handler Methods:**
2831
+ - `onClick(handler)` - Button click events (return `false` to abort, `Promise` to defer)
2832
+ - `onSuccess(handler)` - **Required** - OTT creation success events
2833
+ - `onUnavailable(handler)` - Wallet unavailable events (supports Promise pattern)
2834
+ - `onError(handler)` - Error events (supports Promise pattern)
2835
+ - `onCancel(handler)` - Checkout cancellation events (supports Promise pattern)
2836
+ - `onLoaded(handler)` - Button loaded/rendered events
2837
+ - `onShippingAddressChange(handler)` - **Recommended for shipping** - Address change events (auto-accepted if not registered)
2838
+ - `onShippingOptionsChange(handler)` - **Recommended for shipping options** - Option change events (auto-accepted if not registered)
2839
+
2840
+ **Event Handler Patterns:**
2841
+
2842
+ ```javascript
2843
+ // Required handler
2844
+ button.onSuccess(handler); // Always required
2845
+
2846
+ // Recommended when shipping is enabled (auto-accepted if not registered)
2847
+ button.onShippingAddressChange(handler);
2848
+ button.onShippingOptionsChange(handler);
2849
+
2850
+ // Optional handlers with Promise support
2851
+ button.onUnavailable(handler); // or await button.onUnavailable()
2852
+ button.onError(handler); // or await button.onError()
2853
+ button.onCancel(handler); // or await button.onCancel()
2854
+
2855
+ // Click handler with flow control
2856
+ button.onClick(handler); // Return false to abort, or a Promise to defer
2857
+
2858
+ // Loaded handler
2859
+ button.onLoaded(handler); // Notified when button renders
2860
+ ```
2861
+
2862
+ ### Apple Pay-Specific Meta Properties
2863
+
2864
+ A full description of the [ApplePayOpenWalletMeta](#ApplePayOpenWalletMeta) properties:
2865
+
2866
+ **Required:**
2867
+ - `amount`: The payment amount (number)
2868
+ - `currency`: The currency code (string, e.g., "AUD")
2869
+ - `country`: The country code (string, e.g., "AU")
2870
+ - `amount_label`: Label for the total amount (string)
2871
+ - `store_name`: Merchant store name (string)
2872
+
2873
+ **Optional:**
2874
+ - `request_shipping?: boolean`: Enable shipping address collection
2875
+ - `shipping_options?: IApplePayShippingOption[]`: Array of shipping options
2876
+ - `show_billing_address?: boolean`: Show billing address fields
2877
+ - `apple_pay_capabilities?: string[]`: Device capabilities
2878
+ - `merchant_capabilities?: string[]`: Merchant capabilities
2879
+ - `supported_networks?: string[]`: Supported payment networks
2880
+ - `required_billing_contact_fields?: string[]`: Required billing contact fields
2881
+ - `required_shipping_contact_fields?: string[]`: Required shipping contact fields
2882
+ - `supported_countries?: string[]`: Supported countries
2883
+ - `shipping_editing_mode?: 'available' | 'store_pickup'`: Shipping address editing mode
2884
+ - `style?: { button_type?: ApplePayButtonType, button_style?: ApplePayButtonStyle }`: Button styling
2885
+
2886
+ ### Google Pay-Specific Meta Properties
2887
+
2888
+ A full description of the [GooglePayOpenWalletMeta](#GooglePayOpenWalletMeta) 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
+
2895
+ **Optional:**
2896
+ - `amount_label?: string`: Label for the total amount
2897
+ - `merchant_name?: string`: Display name for the merchant
2898
+ - `request_shipping?: boolean`: Enable shipping address collection
2899
+ - `shipping_options?: IGooglePayShippingOption[]`: Array of shipping options
2900
+ - `show_billing_address?: boolean`: Show billing address fields
2901
+ - `card_config?: GooglePayCardConfig`: Card configuration (auth methods, networks, tokenization)
2902
+ - `style?: { button_type?: GooglePayButtonType, button_color?: GooglePayButtonColor, button_size_mode?: GooglePayButtonSizeMode }`: Button styling
2903
+
2904
+ ### Shipping Options Format
2905
+ ```javascript
2906
+ shipping_options: [
2907
+ {
2908
+ id: "option_id", // Unique identifier (string)
2909
+ label: "Option Name", // Display name (string)
2910
+ detail: "Description", // Optional description (string)
2911
+ amount: 10.00, // Shipping cost as number
2912
+ date_components_range: { // Optional: delivery date range (Apple Pay only)
2913
+ start_date_components: {
2914
+ years: 0,
2915
+ months: 0,
2916
+ days: 5,
2917
+ hours: 0,
2918
+ },
2919
+ end_date_components: {
2920
+ years: 0,
2921
+ months: 0,
2922
+ days: 10,
2923
+ hours: 0,
2924
+ }
2925
+ }
2926
+ }
2927
+ ]
2928
+ ```
2929
+
2930
+ **Important**:
2931
+ - `amount` should be a **number**, not a string
2932
+ - `date_components_range` is optional but provides delivery estimates (Apple Pay only)
2933
+ - Updated shipping options returned from event handlers don't require `date_components_range`
2934
+
2935
+ ### Environment Setup
2936
+ ```javascript
2937
+ // Always set environment before loading
2938
+ button.setEnv('sandbox');
2939
+ button.load();
2940
+ ```
2941
+
2942
+ ### Error Handling Best Practices
2943
+ ```javascript
2944
+ button.onError(function({ data }) {
2945
+ console.error('Full error object:', data);
2946
+
2947
+ const errorMessage = data.error?.message || 'Unknown error occurred';
2948
+
2949
+ if (data.context?.operation === 'wallet_operation') {
2950
+ showWalletError(errorMessage);
2951
+ } else {
2952
+ showGeneralError(errorMessage);
2953
+ }
2954
+ });
2955
+ ```
2956
+
1314
2957
  # Click To Pay
1315
2958
 
1316
2959
  ## Overview