@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
@@ -2,11 +2,16 @@
2
2
  You can find description of all methods and parameters [here](https://www.npmjs.com/package/@paydock/client-sdk#open-wallet-buttons-simple-example)
3
3
 
4
4
  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.
5
- Currently supports Apple Pay and Google Pay, with more wallet types planned for future releases.
5
+
6
+ Each wallet type has its own dedicated class with fully typed metadata:
7
+ - [ApplePayOpenWalletButton](#ApplePayOpenWalletButton) - for Apple Pay integration
8
+ - [GooglePayOpenWalletButton](#GooglePayOpenWalletButton) - for Google Pay integration
9
+
10
+ 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.
6
11
 
7
12
  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.
8
13
 
9
- ## Open Wallet Buttons simple example
14
+ ## Apple Pay Open Wallet Button
10
15
 
11
16
  ### Container
12
17
 
@@ -14,103 +19,58 @@ If available in your client environment, you will display a simple button that u
14
19
  <div id="widget"></div>
15
20
  ```
16
21
 
17
- You must create a container for the Open Wallet Buttons. Inside this tag, the button will be initialized.
22
+ You must create a container for the Open Wallet Button. Inside this tag, the button will be initialized.
18
23
 
19
- Before initializing the button, you must configure your wallet service through the PayDock dashboard and obtain the service ID that will be used to load the button configuration.
24
+ 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.
20
25
 
21
26
  ### Initialization
22
27
 
23
- For Apple Pay and Google Pay wallets, the amount and currency are required:
24
-
25
- **Apple Pay Example:**
26
- ```javascript
27
- let button = new paydock.OpenWalletButtons(
28
- "#widget",
29
- publicKeyOrAccessToken,
30
- serviceId,
31
- {
32
- amount: 100,
33
- currency: "USD",
34
- },
35
- [] // Optional: required meta fields validation
36
- );
37
- button.load();
38
- ```
39
-
40
- **Google Pay Example:**
41
28
  ```javascript
42
- let button = new paydock.OpenWalletButtons(
29
+ let button = new paydock.ApplePayOpenWalletButton(
43
30
  "#widget",
44
31
  publicKeyOrAccessToken,
45
32
  serviceId,
46
33
  {
47
34
  amount: 100,
48
- currency: "USD",
49
- merchant_name: "Your Store"
50
- },
51
- [] // Optional: required meta fields validation
35
+ currency: "AUD",
36
+ country: "AU",
37
+ amount_label: "TOTAL",
38
+ store_name: "My Store",
39
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
40
+ }
52
41
  );
53
42
  button.load();
54
43
  ```
55
44
 
56
45
  ```javascript
57
46
  // ES2015 | TypeScript
58
- import { OpenWalletButtons } from '@paydock/client-sdk';
47
+ import { ApplePayOpenWalletButton } from '@paydock/client-sdk';
59
48
 
60
- var button = new OpenWalletButtons(
49
+ var button = new ApplePayOpenWalletButton(
61
50
  '#widget',
62
51
  publicKeyOrAccessToken,
63
52
  serviceId,
64
53
  {
65
54
  amount: 100,
66
- currency: 'USD',
67
- },
68
- [] // Optional: required meta fields validation
69
- );
70
- button.load();
71
- ```
72
-
73
- For Apple Pay with shipping enabled:
74
- ```javascript
75
- let button = new paydock.OpenWalletButtons(
76
- "#widget",
77
- publicKeyOrAccessToken,
78
- serviceId,
79
- {
80
- amount: 100,
81
- currency: "USD",
82
- amount_label: "Total",
83
- country: "US",
84
- request_shipping: true,
85
- shipping_options: [
86
- {
87
- id: "standard",
88
- label: "Standard Shipping",
89
- detail: "5-7 business days",
90
- amount: 5.00
91
- },
92
- {
93
- id: "express",
94
- label: "Express Shipping",
95
- detail: "1-2 business days",
96
- amount: 15.00
97
- }
98
- ]
99
- },
100
- ['amount_label', 'country', 'request_shipping'] // Required meta fields validation
55
+ currency: 'AUD',
56
+ country: 'AU',
57
+ amount_label: 'TOTAL',
58
+ store_name: 'My Store',
59
+ }
101
60
  );
102
61
  button.load();
103
62
  ```
104
63
 
105
64
  ### Constructor Parameters
106
65
 
107
- The OpenWalletButtons constructor accepts the following parameters:
66
+ The ApplePayOpenWalletButton constructor accepts the following parameters:
108
67
 
109
68
  1. **selector** (string): CSS selector for the container element
110
69
  2. **publicKeyOrAccessToken** (string): Your PayDock public key or access token
111
- 3. **serviceId** (string): The service ID configured in PayDock dashboard
112
- 4. **meta** (OpenWalletMeta): Configuration object with payment and wallet settings
113
- 5. **requiredMetaFields** (string[], optional): Array of meta field names that must be present
70
+ 3. **serviceId** (string): The Apple Pay service ID configured in PayDock dashboard
71
+ 4. **meta** (ApplePayOpenWalletMeta): Apple Pay-specific configuration object
72
+
73
+ > **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.
114
74
 
115
75
  ### Setting environment
116
76
 
@@ -121,202 +81,7 @@ Bear in mind that you must set an environment before calling `button.load()`.
121
81
  button.setEnv('sandbox');
122
82
  ```
123
83
 
124
- ### Full example
125
-
126
- ```html
127
- <!DOCTYPE html>
128
- <html lang="en">
129
- <head>
130
- <meta charset="UTF-8">
131
- <title>Title</title>
132
- </head>
133
- <body>
134
- <h2>Payment using PayDock Open Wallet Button!</h2>
135
- <div id="widget"></div>
136
- </body>
137
- <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
138
- <script>
139
- let button = new paydock.OpenWalletButtons(
140
- "#widget",
141
- publicKeyOrAccessToken,
142
- serviceId,
143
- {
144
- amount: 100,
145
- currency: "USD",
146
- amount_label: "Total",
147
- country: "US",
148
- },
149
- ['amount', 'currency'] // Required meta fields
150
- );
151
- button.load();
152
- </script>
153
- </html>
154
- ```
155
-
156
- ## Open Wallet Buttons advanced example
157
-
158
- ### Checking for button availability
159
-
160
- 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.
161
-
162
- ```javascript
163
- button.onUnavailable((data) => console.log("No open wallet buttons available", data));
164
- ```
165
-
166
- ### Performing actions when the wallet button is clicked
167
-
168
- 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.
169
-
170
- ```javascript
171
- // Synchronous example
172
- button.onClick((data) => {
173
- console.log("Perform actions on button click");
174
- // Perform validation logic
175
- // Optionally use attachResult to control flow
176
- data.attachResult(true); // Continue with payment
177
- // data.attachResult(false); // Halt payment
178
- });
179
-
180
- // Asynchronous example
181
- button.onClick((data) => {
182
- // Attach a Promise to control the wallet flow
183
- data.attachResult(
184
- fetch('/api/validate-order')
185
- .then(response => response.json())
186
- .then(result => {
187
- if (!result.valid) {
188
- throw new Error('Order validation failed');
189
- }
190
- return result;
191
- })
192
- );
193
- });
194
- ```
195
-
196
- ### Handling successful OTT creation
197
-
198
- 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.
199
-
200
- ```javascript
201
- button.onSuccess((data) => {
202
- console.log("OTT created successfully:", data.token);
203
- console.log("Amount:", data.amount);
204
- console.log("Shipping:", data.shipping);
205
- console.log("Billing:", data.billing);
206
-
207
- // Use the OTT token to complete payment on your backend
208
- fetch('/api/process-payment', {
209
- method: 'POST',
210
- headers: { 'Content-Type': 'application/json' },
211
- body: JSON.stringify({ ott_token: data.token })
212
- });
213
- });
214
- ```
215
-
216
- **Important**: The `onSuccess` event handler is mandatory. Not providing one will result in an error.
217
-
218
- ### Performing actions when shipping address is updated
219
-
220
- When shipping is enabled and the customer updates their shipping address, you can recalculate shipping costs and update the payment amount. **This handler is required when shipping is enabled** - if no handler is provided, an error will be thrown.
221
-
222
- ```javascript
223
- button.onShippingAddressChange(async (data) => {
224
- console.log("Shipping address updated:", data);
225
- console.log("Address details:", {
226
- country: data.address_country,
227
- state: data.address_state,
228
- city: data.address_city,
229
- postcode: data.address_postcode,
230
- contact: data.contact
231
- });
232
-
233
- // Call your backend to recalculate shipping
234
- const response = await fetch('/api/calculate-shipping', {
235
- method: 'POST',
236
- headers: { 'Content-Type': 'application/json' },
237
- body: JSON.stringify({
238
- address_country: data.address_country,
239
- address_state: data.address_state,
240
- address_city: data.address_city,
241
- address_postcode: data.address_postcode
242
- })
243
- });
244
-
245
- const result = await response.json();
246
-
247
- return {
248
- amount: result.newAmount,
249
- shipping_options: result.availableShippingOptions
250
- };
251
- });
252
- ```
253
-
254
- **Important**: This event handler is required when using shipping functionality.
255
-
256
- ### Performing actions when shipping option is selected
257
-
258
- When the customer selects a different shipping option, you can update the total amount accordingly. **This handler is required when shipping options are provided** - if no handler is provided, an error will be thrown.
259
-
260
- ```javascript
261
- button.onShippingOptionsChange(async (data) => {
262
- console.log("Shipping option selected:", data);
263
- console.log("Selected option:", {
264
- id: data.shipping_option_id,
265
- label: data.label,
266
- detail: data.detail,
267
- amount: data.amount
268
- });
269
-
270
- // Call your backend to update total with new shipping cost
271
- const response = await fetch('/api/update-shipping-cost', {
272
- method: 'POST',
273
- headers: { 'Content-Type': 'application/json' },
274
- body: JSON.stringify({
275
- shipping_option_id: data.shipping_option_id,
276
- shipping_amount: data.amount
277
- })
278
- });
279
-
280
- const result = await response.json();
281
-
282
- // Note: In some implementations, you might need to access data.data.amount
283
- // Check your actual data structure in console.log output
284
- return {
285
- amount: result.newTotalAmount
286
- };
287
- });
288
- ```
289
-
290
- **Important**: This event handler is required when providing shipping options.
291
-
292
- ### Handling errors
293
-
294
- Register a callback function to handle errors that occur during wallet operations.
295
-
296
- ```javascript
297
- button.onError((data) => {
298
- console.error("Open Wallet error:", data.error);
299
- console.log("Error context:", data.context);
300
-
301
- // Show user-friendly error message
302
- showErrorMessage("Payment initialization failed. Please try again.");
303
- });
304
- ```
305
-
306
- ### Handling checkout cancellation
307
-
308
- When the user cancels or closes the wallet payment interface, you can perform cleanup operations.
309
-
310
- ```javascript
311
- button.onCancel((data) => {
312
- console.log("Wallet checkout cancelled", data);
313
-
314
- // Perform cleanup or redirect user
315
- window.location.href = '/checkout';
316
- });
317
- ```
318
-
319
- ### Apple Pay Full example
84
+ ### Full Apple Pay example
320
85
 
321
86
  ```html
322
87
  <!DOCTYPE html>
@@ -326,20 +91,21 @@ button.onCancel((data) => {
326
91
  <title>Apple Pay with Open Wallets</title>
327
92
  </head>
328
93
  <body>
329
- <h2>Payment using PayDock Open Wallet Button!</h2>
94
+ <h2>Payment using PayDock Apple Pay Open Wallet Button!</h2>
330
95
  <div id="widget"></div>
331
96
  </body>
332
97
  <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
333
98
  <script>
334
- let button = new paydock.OpenWalletButtons(
99
+ let button = new paydock.ApplePayOpenWalletButton(
335
100
  "#widget",
336
101
  publicKeyOrAccessToken,
337
102
  serviceId,
338
103
  {
339
104
  amount: 100,
340
- currency: "USD",
341
- amount_label: "Total",
342
- country: "US",
105
+ currency: "AUD",
106
+ country: "AU",
107
+ amount_label: "TOTAL",
108
+ store_name: "My Store",
343
109
  request_shipping: true,
344
110
  request_payer_name: true,
345
111
  request_payer_email: true,
@@ -392,57 +158,49 @@ button.onCancel((data) => {
392
158
  }
393
159
  ],
394
160
  apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
395
- },
396
- ['amount_label', 'country', 'request_shipping', 'shipping_options', 'apple_pay_capabilities'] // Required fields validation
161
+ }
397
162
  );
398
-
163
+
399
164
  button.setEnv('sandbox');
400
-
401
- button.onUnavailable((data) => {
165
+
166
+ button.onUnavailable(({ data }) => {
402
167
  console.log("Apple Pay not available:", data);
403
- // Show alternative payment methods
404
168
  });
405
-
406
- button.onClick((data) => {
169
+
170
+ button.onClick(() => {
407
171
  console.log("Apple Pay button clicked");
408
- // Perform pre-payment validation
409
172
  });
410
-
411
- button.onSuccess((data) => {
173
+
174
+ button.onSuccess(({ data }) => {
412
175
  console.log("Payment successful:", data);
413
- // Process the OTT token on your backend
414
176
  processPayment(data.token);
415
177
  });
416
-
417
- button.onError((data) => {
178
+
179
+ button.onError(({ data }) => {
418
180
  console.error("Payment error:", data);
419
- // Handle error appropriately
420
181
  });
421
-
422
- button.onCancel((data) => {
182
+
183
+ button.onCancel(() => {
423
184
  console.log("Payment cancelled");
424
- // Handle cancellation
425
185
  });
426
-
427
- button.onShippingAddressChange(async (addressData) => {
428
- // Update shipping costs based on address
429
- const response = await updateShippingCosts(addressData);
186
+
187
+ button.onShippingAddressChange(async ({ data }) => {
188
+ const response = await updateShippingCosts(data);
430
189
  return {
431
190
  amount: response.newAmount,
432
191
  shipping_options: response.shippingOptions
433
192
  };
434
193
  });
435
-
436
- button.onShippingOptionsChange(async (optionData) => {
437
- // Update total based on selected shipping option
438
- const response = await updateTotal(optionData);
194
+
195
+ button.onShippingOptionsChange(async ({ data }) => {
196
+ const response = await updateTotal(data);
439
197
  return {
440
198
  amount: response.newAmount
441
199
  };
442
200
  });
443
-
201
+
444
202
  button.load();
445
-
203
+
446
204
  async function updateShippingCosts(addressData) {
447
205
  // Your shipping calculation logic based on address
448
206
  const baseAmount = 100;
@@ -460,25 +218,22 @@ button.onCancel((data) => {
460
218
  amount: 18.00
461
219
  }
462
220
  ];
463
-
221
+
464
222
  return {
465
223
  newAmount: baseAmount + updatedShippingOptions[0].amount,
466
224
  shippingOptions: updatedShippingOptions
467
225
  };
468
226
  }
469
-
470
- async function updateTotal(optionData) {
471
- // Your total calculation logic
227
+
228
+ async function updateTotal(shippingOption) {
472
229
  const baseAmount = 100;
473
- // Note: Check if you need data.data.amount or data.amount based on your implementation
474
- const shippingAmount = optionData.amount || optionData.data?.amount;
230
+ const shippingAmount = shippingOption.amount;
475
231
  return {
476
232
  newAmount: baseAmount + shippingAmount
477
233
  };
478
234
  }
479
-
235
+
480
236
  function processPayment(ottToken) {
481
- // Send OTT token to your backend for payment processing
482
237
  fetch('/api/process-payment', {
483
238
  method: 'POST',
484
239
  headers: { 'Content-Type': 'application/json' },
@@ -489,7 +244,262 @@ button.onCancel((data) => {
489
244
  </html>
490
245
  ```
491
246
 
492
- ### Google Pay Full Example
247
+ ### Apple Pay with Shipping
248
+
249
+ For Apple Pay with shipping enabled:
250
+ ```javascript
251
+ let button = new paydock.ApplePayOpenWalletButton(
252
+ "#widget",
253
+ publicKeyOrAccessToken,
254
+ serviceId,
255
+ {
256
+ amount: 100,
257
+ currency: "AUD",
258
+ country: "AU",
259
+ amount_label: "TOTAL",
260
+ store_name: "My Store",
261
+ request_shipping: true,
262
+ shipping_editing_mode: 'available',
263
+ required_shipping_contact_fields: [
264
+ 'postalAddress',
265
+ 'name',
266
+ 'phone',
267
+ 'email',
268
+ ],
269
+ shipping_options: [
270
+ {
271
+ id: "standard",
272
+ label: "Standard Shipping",
273
+ detail: "5-7 business days",
274
+ amount: 5.00
275
+ },
276
+ {
277
+ id: "express",
278
+ label: "Express Shipping",
279
+ detail: "1-2 business days",
280
+ amount: 15.00
281
+ }
282
+ ],
283
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
284
+ }
285
+ );
286
+ button.load();
287
+ ```
288
+
289
+ 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.
290
+
291
+ ```javascript
292
+ button.onShippingAddressChange(async function({ data }) {
293
+ console.log("Shipping address has been updated", data);
294
+ return {
295
+ amount: newAmount,
296
+ shipping_options: updatedShippingOptions
297
+ };
298
+ });
299
+
300
+ button.onShippingOptionsChange(async function({ data }) {
301
+ console.log("Shipping option selected", data);
302
+ return {
303
+ amount: newTotalAmount
304
+ };
305
+ });
306
+ ```
307
+
308
+ ### Supported Shipping Cases
309
+
310
+ #### Injected Shipping Address, non-editable by the customer
311
+
312
+ 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.
313
+
314
+ The required meta parameters for this case are:
315
+ - shipping_editing_mode: 'store_pickup'
316
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
317
+
318
+ ```javascript
319
+ meta: {
320
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
321
+ amount_label: 'TOTAL',
322
+ country: 'AU',
323
+ currency: 'AUD',
324
+ amount: 10,
325
+ shipping_editing_mode: 'store_pickup',
326
+ required_shipping_contact_fields: [
327
+ 'postalAddress',
328
+ 'name',
329
+ 'phone',
330
+ 'email',
331
+ ],
332
+ shipping: {
333
+ amount: 5,
334
+ address_line1: "Address Line 1",
335
+ address_city: "Test Locality",
336
+ address_state: "NSW",
337
+ address_country: "Australia",
338
+ address_country_code: "AU",
339
+ address_postcode: "3000",
340
+ contact: {
341
+ phone: "+61400245562",
342
+ email: "test@example.com",
343
+ first_name: "QA",
344
+ last_name: "QA",
345
+ },
346
+ options: [
347
+ {
348
+ label: "Test 1",
349
+ detail: "This is a test 1 shipping methods",
350
+ amount: 10,
351
+ id: "randomId1",
352
+ }
353
+ ],
354
+ },
355
+ }
356
+ ```
357
+
358
+ #### Injected Shipping Address, editable by the customer
359
+
360
+ 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.
361
+
362
+ The required meta parameters for this case are:
363
+ - shipping_editing_mode: 'available'
364
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
365
+
366
+ ```javascript
367
+ meta: {
368
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
369
+ amount_label: 'TOTAL',
370
+ country: 'AU',
371
+ currency: 'AUD',
372
+ amount: 10,
373
+ shipping_editing_mode: 'available',
374
+ required_shipping_contact_fields: [
375
+ 'postalAddress',
376
+ 'name',
377
+ 'phone',
378
+ 'email',
379
+ ],
380
+ shipping: {
381
+ amount: 5,
382
+ address_line1: "Address Line 1",
383
+ address_city: "Test Locality",
384
+ address_state: "NSW",
385
+ address_country: "Australia",
386
+ address_country_code: "AU",
387
+ address_postcode: "3000",
388
+ contact: {
389
+ phone: "+61400245562",
390
+ email: "test@example.com",
391
+ first_name: "QA",
392
+ last_name: "QA",
393
+ },
394
+ options: [
395
+ {
396
+ label: "Test 1",
397
+ detail: "This is a test 1 shipping methods",
398
+ amount: 10,
399
+ id: "randomId1",
400
+ }
401
+ ],
402
+ },
403
+ }
404
+ ```
405
+
406
+ #### Shipping address editable by the customer (no pre-filled address)
407
+
408
+ 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.
409
+
410
+ The required meta parameters for this case are:
411
+ - shipping_editing_mode: 'available'
412
+ - required_shipping_contact_fields: ['postalAddress'] <-- At least one of the fields is required so the shipping address is shown at Apple Pay.
413
+
414
+ ```javascript
415
+ meta: {
416
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable'],
417
+ amount_label: 'TOTAL',
418
+ country: 'AU',
419
+ currency: 'AUD',
420
+ amount: 10,
421
+ shipping_editing_mode: 'available',
422
+ required_shipping_contact_fields: [
423
+ 'postalAddress',
424
+ 'name',
425
+ 'phone',
426
+ 'email',
427
+ ],
428
+ }
429
+ ```
430
+
431
+ #### No shipping address
432
+
433
+ 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.
434
+
435
+ **Important:**
436
+ - No shipping address should be provided in the meta object.
437
+ - Shipping address could be provided in the initial POST `/v1/charges/wallet` endpoint, if collected previously.
438
+
439
+ The required meta parameters for this case are:
440
+ - `required_shipping_contact_fields`: Only include contact fields if needed (phone, email), but NOT `postalAddress`.
441
+
442
+ ```javascript
443
+ meta: {
444
+ amount_label: "TOTAL",
445
+ country: "AU",
446
+ currency: "AUD",
447
+ amount: 10,
448
+ shipping_editing_mode: "available",
449
+ required_shipping_contact_fields: ["phone", "email"],
450
+ apple_pay_capabilities: ["credentials_available", "credentials_status_unknown", "credentials_unavailable"]
451
+ }
452
+ ```
453
+
454
+ ## Google Pay Open Wallet Button
455
+
456
+ ### Initialization
457
+
458
+ ```javascript
459
+ let button = new paydock.GooglePayOpenWalletButton(
460
+ "#widget",
461
+ publicKeyOrAccessToken,
462
+ serviceId,
463
+ {
464
+ amount: 100,
465
+ currency: "AUD",
466
+ country: "AU",
467
+ merchant_name: "Your Store",
468
+ }
469
+ );
470
+ button.load();
471
+ ```
472
+
473
+ ```javascript
474
+ // ES2015 | TypeScript
475
+ import { GooglePayOpenWalletButton } from '@paydock/client-sdk';
476
+
477
+ var button = new GooglePayOpenWalletButton(
478
+ '#widget',
479
+ publicKeyOrAccessToken,
480
+ serviceId,
481
+ {
482
+ amount: 100,
483
+ currency: 'AUD',
484
+ country: 'AU',
485
+ merchant_name: 'Your Store',
486
+ }
487
+ );
488
+ button.load();
489
+ ```
490
+
491
+ ### Constructor Parameters
492
+
493
+ The GooglePayOpenWalletButton constructor accepts the following parameters:
494
+
495
+ 1. **selector** (string): CSS selector for the container element
496
+ 2. **publicKeyOrAccessToken** (string): Your PayDock public key or access token
497
+ 3. **serviceId** (string): The Google Pay service ID configured in PayDock dashboard
498
+ 4. **meta** (GooglePayOpenWalletMeta): Google Pay-specific configuration object
499
+
500
+ > **Note:** Required meta fields (`amount`, `currency`, `country`) are validated automatically by the `GooglePayOpenWalletButton` class. You do not need to specify them manually.
501
+
502
+ ### Full Google Pay Example
493
503
 
494
504
  ```html
495
505
  <!DOCTYPE html>
@@ -504,30 +514,23 @@ button.onCancel((data) => {
504
514
  </body>
505
515
  <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js" ></script>
506
516
  <script>
507
- let button = new paydock.OpenWalletButtons(
517
+ let button = new paydock.GooglePayOpenWalletButton(
508
518
  "#widget",
509
519
  publicKeyOrAccessToken,
510
520
  serviceId,
511
521
  {
512
522
  amount: 100,
513
- currency: "USD",
514
- amount_label: "Total",
523
+ currency: "AUD",
515
524
  country: "AU",
525
+ amount_label: "Total",
516
526
  request_shipping: true,
517
527
  show_billing_address: true,
518
528
  merchant_name: 'Test Merchant',
519
529
  style: {
520
- google: {
521
- button_type: 'buy',
522
- button_color: 'default',
523
- button_size_mode: 'fill'
524
- }
530
+ button_type: 'buy',
531
+ button_color: 'default',
532
+ button_size_mode: 'fill'
525
533
  },
526
- // Google Pay specific properties
527
- payment_method_type: 'CARD',
528
- allowed_auth_methods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
529
- allowed_card_networks: ['AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'],
530
- billing_address_required: true,
531
534
  shipping_options: [
532
535
  {
533
536
  id: "standard",
@@ -539,64 +542,56 @@ button.onCancel((data) => {
539
542
  {
540
543
  id: "express",
541
544
  label: "Express Shipping",
542
- detail: "Arrives in 1 to 2 days",
545
+ detail: "Arrives in 1 to 2 days",
543
546
  amount: 15.00,
544
547
  type: "PICKUP"
545
548
  }
546
549
  ]
547
- },
548
- ['amount_label', 'country', 'request_shipping', 'shipping_options', 'merchant_name']
550
+ }
549
551
  );
550
-
552
+
551
553
  button.setEnv('sandbox');
552
-
553
- // Required handlers
554
- button.onSuccess((data) => {
554
+
555
+ button.onSuccess(({ data }) => {
555
556
  console.log("Payment successful:", data);
556
557
  processPayment(data.token);
557
558
  });
558
-
559
- button.onShippingAddressChange(async (addressData) => {
560
- const response = await updateShippingCosts(addressData);
559
+
560
+ button.onShippingAddressChange(async ({ data }) => {
561
+ const response = await updateShippingCosts(data);
561
562
  return {
562
563
  amount: response.newAmount,
563
564
  shipping_options: response.shippingOptions
564
565
  };
565
566
  });
566
-
567
- button.onShippingOptionsChange(async (optionData) => {
568
- const response = await updateTotal(optionData);
567
+
568
+ button.onShippingOptionsChange(async ({ data }) => {
569
+ const response = await updateTotal(data);
569
570
  return {
570
571
  amount: response.newAmount
571
572
  };
572
573
  });
573
-
574
- // Optional handlers
575
- button.onUnavailable((data) => {
574
+
575
+ button.onUnavailable(({ data }) => {
576
576
  console.log("Google Pay not available:", data);
577
- // Show alternative payment methods
578
577
  });
579
-
580
- button.onError((data) => {
578
+
579
+ button.onError(({ data }) => {
581
580
  console.error("Payment error:", data);
582
- // Handle error appropriately
583
581
  });
584
-
585
- button.onCancel((data) => {
582
+
583
+ button.onCancel(() => {
586
584
  console.log("Payment cancelled");
587
- // Handle cancellation
588
585
  });
589
-
590
- button.onClick((data) => {
586
+
587
+ button.onClick(() => {
591
588
  console.log("Google Pay button clicked");
592
- // Perform pre-payment validation
593
589
  });
594
-
590
+
595
591
  button.load();
596
-
597
- // Helper functions (same implementation as Apple Pay example)
592
+
593
+ // Helper functions
598
594
  async function updateShippingCosts(addressData) {
599
- // Your shipping calculation logic based on address
600
595
  const baseAmount = 100;
601
596
  const updatedShippingOptions = [
602
597
  {
@@ -614,24 +609,22 @@ button.onCancel((data) => {
614
609
  type: "PICKUP"
615
610
  }
616
611
  ];
617
-
612
+
618
613
  return {
619
614
  newAmount: baseAmount + updatedShippingOptions[0].amount,
620
615
  shippingOptions: updatedShippingOptions
621
616
  };
622
617
  }
623
-
624
- async function updateTotal(optionData) {
625
- // Your total calculation logic
618
+
619
+ async function updateTotal(shippingOption) {
626
620
  const baseAmount = 100;
627
- const shippingAmount = optionData.amount || optionData.data?.amount;
621
+ const shippingAmount = shippingOption.amount;
628
622
  return {
629
623
  newAmount: baseAmount + shippingAmount
630
624
  };
631
625
  }
632
-
626
+
633
627
  function processPayment(ottToken) {
634
- // Send OTT token to your backend for payment processing
635
628
  fetch('/api/process-payment', {
636
629
  method: 'POST',
637
630
  headers: { 'Content-Type': 'application/json' },
@@ -642,264 +635,207 @@ button.onCancel((data) => {
642
635
  </html>
643
636
  ```
644
637
 
645
- ### Events
646
- 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 OpenWalletButtons class.
638
+ ## Common API
647
639
 
648
- **Available Event Handler Methods:**
649
- - `onClick(handler)` - Button click events (supports attachResult for flow control)
650
- - `onSuccess(handler)` - **Required** - OTT creation success events
651
- - `onUnavailable(handler)` - Wallet unavailable events (supports Promise pattern)
652
- - `onError(handler)` - Error events (supports Promise pattern)
653
- - `onCancel(handler)` - Checkout cancellation events (supports Promise pattern)
654
- - `onShippingAddressChange(handler)` - **Required for shipping** - Address change events
655
- - `onShippingOptionsChange(handler)` - **Required for shipping options** - Option change events
656
-
657
- **Event Handler Patterns:**
640
+ Both `ApplePayOpenWalletButton` and `GooglePayOpenWalletButton` share the same event handler API inherited from the base class.
658
641
 
659
- ```javascript
660
- // Required handlers (will throw error if not provided)
661
- button.onSuccess(handler); // Always required
662
- button.onShippingAddressChange(handler); // Required when shipping enabled
663
- button.onShippingOptionsChange(handler); // Required when shipping options provided
642
+ ### Checking for button availability
664
643
 
665
- // Optional handlers with Promise support
666
- button.onUnavailable(handler); // or await button.onUnavailable()
667
- button.onError(handler); // or await button.onError()
668
- button.onCancel(handler); // or await button.onCancel()
644
+ 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.
669
645
 
670
- // Click handler with flow control
671
- button.onClick(handler); // Use data.attachResult() for async operations
646
+ ```javascript
647
+ button.onUnavailable(({ data }) => console.log("No wallet button available", data));
672
648
  ```
673
649
 
674
- ### Configuration Options
650
+ ### Service type validation
675
651
 
676
- #### Required Meta Fields
652
+ 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`:
677
653
 
678
- - `amount`: The payment amount (number)
679
- - `currency`: The currency code (string, e.g., "USD")
654
+ ```javascript
655
+ // This will raise an error if the service ID does not correspond to a Google Pay service
656
+ let button = new paydock.GooglePayOpenWalletButton(
657
+ "#widget",
658
+ publicKeyOrAccessToken,
659
+ applePayServiceId, // Wrong! This is an Apple Pay service ID
660
+ meta
661
+ );
680
662
 
681
- #### PayDock-Specific Meta Fields
663
+ button.onError(({ data }) => {
664
+ // Error: Service configuration type 'ApplePay' does not match expected wallet type 'google'.
665
+ console.error(data.error.message);
666
+ });
682
667
 
683
- The following are PayDock-specific properties available in `OpenWalletMeta`:
668
+ button.load();
669
+ ```
684
670
 
685
- **Payment Configuration:**
686
- - `amount_label?: string`: Label for the total amount
687
- - `country?: string`: Country code (e.g., "US")
688
- - `capture?: boolean`: Whether to capture the payment immediately
689
- - `reference?: string`: Payment reference
690
- - `id?: string`: Payment ID
691
- - `credentials?: object`: Gateway credentials
671
+ ### Performing actions when the wallet button is clicked
672
+
673
+ 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.
692
674
 
693
- **Contact and Shipping:**
694
- - `request_shipping?: boolean`: Enable shipping address collection
695
- - `request_payer_name?: boolean`: Request payer name
696
- - `request_payer_email?: boolean`: Request payer email
697
- - `request_payer_phone?: boolean`: Request payer phone
698
- - `show_billing_address?: boolean`: Show billing address fields
699
- - `shipping_options?: IShippingOption[]`: Array of shipping options
700
-
701
- **UI and Display:**
702
- - `style?: WalletStyles`: Button styling options
703
- - `pay_later?: boolean`: Enable pay later options
704
- - `hide_message?: boolean`: Hide payment messages
705
- - `standalone?: boolean`: Standalone mode
706
- - `merchant_name?: string`: Merchant display name
707
-
708
- **Wallet-Specific:**
709
- - `apple_pay_capabilities?: string[]`: Apple Pay capability requirements
710
- - `wallets?: WALLET_TYPES[]`: Supported wallet types
711
- - `access_token?: string`: Access token
712
- - `refresh_token?: string`: Refresh token
713
- - `client_id?: string`: Client ID
714
-
715
- #### Extended Native Properties
716
- Since `OpenWalletMeta` extends `ApplePayJS.ApplePayPaymentRequest` and Google Pay interfaces, you can use any native Apple Pay or Google Pay properties directly in the configuration object alongside PayDock properties. See the [Extended Interface Properties](#extended-interface-properties) section for comprehensive details.
717
-
718
- #### Configuration Comparison Quick Reference
719
-
720
- | Feature | PayDock Property | Apple Pay Native Property | Google Pay Native Property |
721
- |---------|------------------|---------------------------|----------------------------|
722
- | **Country** | `country: 'US'` | `countryCode: 'US'` | `parameters.allowedCountries: ['US']` |
723
- | **Currency** | `currency: 'USD'` | `currencyCode: 'USD'` | Via PayDock property |
724
- | **Amount** | `amount: 100` | `total: { amount: '100.00' }` | Via PayDock property |
725
- | **Billing Address** | `show_billing_address: true` | `requiredBillingContactFields: [...]` | `billingAddressRequired: true` |
726
- | **Shipping Address** | `request_shipping: true` | `requiredShippingContactFields: [...]` | `shippingAddressRequired: true` |
727
- | **Card Networks** | Auto-configured | `supportedNetworks: ['visa', ...]` | `allowedCardNetworks: ['VISA', ...]` |
728
- | **Button Style** | `style.apple.button_style` | Via PayDock style property | `style.google.button_color` |
729
-
730
- #### Apple Pay Specific Style Options
731
675
  ```javascript
732
- style: {
733
- apple: {
734
- button_type: 'add-money' | 'book' | 'buy' | 'check-out' | 'continue' | 'contribute' | 'donate' | 'order' | 'pay' | 'plain' | 'reload' | 'rent' | 'set-up' | 'subscribe' | 'support' | 'tip' | 'top-up',
735
- button_style: 'black' | 'white' | 'white-outline'
736
- },
737
- google: {
738
- button_type: 'book' | 'buy' | 'checkout' | 'donate' | 'order' | 'pay' | 'plain' | 'subscribe',
739
- button_color: 'default' | 'black' | 'white',
740
- button_size_mode: 'static' | 'fill'
676
+ // Synchronous — continue normally
677
+ button.onClick(() => {
678
+ console.log("Perform actions on button click");
679
+ });
680
+
681
+ // Synchronous — return false to abort the payment flow
682
+ button.onClick(() => {
683
+ if (!isOrderValid()) return false;
684
+ });
685
+
686
+ // Asynchronous — defer the wallet sheet until the promise resolves
687
+ button.onClick(async () => {
688
+ const response = await fetch('/api/validate-order');
689
+ const result = await response.json();
690
+ if (!result.valid) {
691
+ throw new Error('Order validation failed');
741
692
  }
742
- }
693
+ });
743
694
  ```
744
695
 
745
- ### Google Pay Specific Properties
696
+ ### Handling successful OTT creation
746
697
 
747
- The following are Google Pay-specific properties available in `GooglePayMeta`:
698
+ 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.
748
699
 
749
- **Payment Method Configuration:**
750
- - `payment_method_type?: google.payments.api.PaymentMethodType`: Payment method type (usually 'CARD')
751
- - `allowed_auth_methods?: google.payments.api.CardAuthMethod[]`: Authentication methods (e.g., ['PAN_ONLY', 'CRYPTOGRAM_3DS'])
752
- - `allowed_card_networks?: google.payments.api.CardNetwork[]`: Supported card networks (e.g., ['AMEX', 'DISCOVER', 'INTERAC', 'JCB', 'MASTERCARD', 'VISA'])
700
+ ```javascript
701
+ button.onSuccess(({ data }) => {
702
+ console.log("OTT created successfully:", data.token);
703
+ console.log("Amount:", data.amount);
704
+ console.log("Shipping:", data.shipping);
705
+ console.log("Billing:", data.billing);
753
706
 
754
- **Billing Address Configuration:**
755
- - `billing_address_required?: boolean`: Override for show_billing_address
756
- - `billing_address_format?: google.payments.api.BillingAddressFormat`: Billing address format specification
707
+ fetch('/api/process-payment', {
708
+ method: 'POST',
709
+ headers: { 'Content-Type': 'application/json' },
710
+ body: JSON.stringify({ ott_token: data.token })
711
+ });
712
+ });
713
+ ```
757
714
 
758
- **Merchant Configuration:**
759
- - `merchant_name?: string`: Display name for the merchant
715
+ **Important**: The `onSuccess` event handler is mandatory. Not providing one will result in an error.
760
716
 
761
- ### Extended Interface Properties
717
+ ### Updating meta after initialization
762
718
 
763
- The `OpenWalletMeta` interface extends native Apple Pay and Google Pay interfaces, giving you access to their native properties alongside PayDock-specific configurations:
719
+ 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:
764
720
 
765
- - Extends `ApplePayJS.ApplePayPaymentRequest` (full Apple Pay interface)
766
- - Extends `google.payments.api.IsReadyToPayPaymentMethodSpecification` (except `tokenizationSpecification`)
767
- - Extends `google.payments.api.PaymentMethodSpecification`
721
+ ```javascript
722
+ // For Apple Pay - accepts ApplePayOpenWalletMeta
723
+ applePayButton.setMeta({ ...meta, amount: 29.99, amount_label: 'NEW TOTAL' });
724
+
725
+ // For Google Pay - accepts GooglePayOpenWalletMeta
726
+ googlePayButton.setMeta({ ...meta, amount: 29.99, merchant_name: 'Updated Store' });
727
+ ```
768
728
 
769
- #### Apple Pay Extended Properties (ApplePayJS.ApplePayPaymentRequest)
729
+ ### Handling errors
770
730
 
771
- Since `OpenWalletMeta` extends `ApplePayJS.ApplePayPaymentRequest`, you can use any native Apple Pay property:
731
+ Register a callback function to handle errors that occur during wallet operations, including service type mismatches.
772
732
 
773
733
  ```javascript
774
- const applePayConfig = {
775
- // PayDock specific properties
776
- amount: 100,
777
- currency: 'USD',
778
- amount_label: 'Total',
779
- country: 'US',
780
-
781
- // Native Apple Pay properties
782
- countryCode: 'US', // Country code for the payment
783
- currencyCode: 'USD', // Currency code for the payment
784
- merchantCapabilities: [ // Merchant capabilities
785
- 'supports3DS',
786
- 'supportsCredit',
787
- 'supportsDebit'
788
- ],
789
- supportedNetworks: [ // Supported card networks
790
- 'visa',
791
- 'masterCard',
792
- 'amex',
793
- 'discover'
794
- ],
795
- requiredBillingContactFields: [ // Required billing fields
796
- 'name',
797
- 'postalAddress',
798
- 'email',
799
- 'phone'
800
- ],
801
- requiredShippingContactFields: [ // Required shipping fields
802
- 'postalAddress',
803
- 'name',
804
- 'phone',
805
- 'email'
806
- ],
807
- supportedCountries: [ // Supported countries for shipping
808
- 'US', 'CA', 'GB'
809
- ],
810
- total: { // Total amount object
811
- label: 'Total',
812
- amount: '100.00',
813
- type: 'final'
814
- },
815
- shippingContact: { // Pre-filled shipping contact
816
- givenName: 'John',
817
- familyName: 'Doe',
818
- emailAddress: 'john@example.com'
819
- },
820
- billingContact: { // Pre-filled billing contact
821
- givenName: 'John',
822
- familyName: 'Doe'
823
- }
824
- };
734
+ button.onError(({ data }) => {
735
+ console.error("Open Wallet error:", data.error);
736
+ console.log("Error context:", data.context);
737
+
738
+ showErrorMessage("Payment initialization failed. Please try again.");
739
+ });
825
740
  ```
826
741
 
827
- #### Google Pay Extended Properties
742
+ ### Handling checkout cancellation
828
743
 
829
- Since `OpenWalletMeta` extends Google Pay interfaces, you can use native Google Pay properties:
744
+ When the user cancels or closes the wallet payment interface, you can perform cleanup operations.
830
745
 
831
746
  ```javascript
832
- const googlePayConfig = {
833
- // PayDock specific properties
834
- amount: 100,
835
- currency: 'USD',
836
- amount_label: 'Total',
837
- country: 'US',
838
-
839
- // Native Google Pay properties (from IsReadyToPayPaymentMethodSpecification)
840
- type: 'CARD', // Payment method type
841
- parameters: {
842
- allowedAuthMethods: [ // Allowed authentication methods
843
- 'PAN_ONLY',
844
- 'CRYPTOGRAM_3DS'
845
- ],
846
- allowedCardNetworks: [ // Allowed card networks
847
- 'AMEX',
848
- 'DISCOVER',
849
- 'JCB',
850
- 'MASTERCARD',
851
- 'VISA'
852
- ],
853
- billingAddressRequired: true, // Require billing address
854
- billingAddressParameters: { // Billing address parameters
855
- format: 'FULL',
856
- phoneNumberRequired: true
857
- }
858
- },
859
-
860
- // Note: tokenizationSpecification is omitted from OpenWalletMeta
861
- // as it's handled automatically by PayDock
862
- };
747
+ button.onCancel(() => {
748
+ console.log("Wallet checkout cancelled");
749
+ window.location.href = '/checkout';
750
+ });
863
751
  ```
864
752
 
865
- #### Property Inheritance
753
+ ### Cleaning up
754
+
755
+ Remove the wallet button from the DOM when it is no longer needed:
756
+
757
+ ```javascript
758
+ button.destroy();
759
+ ```
866
760
 
867
- Since `OpenWalletMeta` extends native Apple Pay and Google Pay interfaces, you get access to both:
761
+ ### Events
762
+ 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.
868
763
 
869
- 1. **PayDock Properties**: Simplified, cross-wallet properties (e.g., `amount`, `currency`, `country`)
870
- 2. **Native Extended Properties**: Full native wallet properties (e.g., `merchantCapabilities`, `supportedNetworks`)
764
+ **Available Event Handler Methods:**
765
+ - `onClick(handler)` - Button click events (return `false` to abort, `Promise` to defer)
766
+ - `onSuccess(handler)` - **Required** - OTT creation success events
767
+ - `onUnavailable(handler)` - Wallet unavailable events (supports Promise pattern)
768
+ - `onError(handler)` - Error events (supports Promise pattern)
769
+ - `onCancel(handler)` - Checkout cancellation events (supports Promise pattern)
770
+ - `onLoaded(handler)` - Button loaded/rendered events
771
+ - `onShippingAddressChange(handler)` - **Recommended for shipping** - Address change events (auto-accepted if not registered)
772
+ - `onShippingOptionsChange(handler)` - **Recommended for shipping options** - Option change events (auto-accepted if not registered)
871
773
 
872
- Both types of properties can be used together in the same configuration object:
774
+ **Event Handler Patterns:**
873
775
 
874
776
  ```javascript
875
- // Example combining PayDock and native properties
876
- const config = {
877
- // PayDock simplified properties
878
- amount: 100,
879
- currency: 'USD',
880
- country: 'US',
881
- show_billing_address: true,
882
-
883
- // Native Apple Pay properties (available due to interface extension)
884
- merchantCapabilities: ['supports3DS', 'supportsCredit'],
885
- supportedNetworks: ['visa', 'masterCard', 'amex'],
886
- requiredBillingContactFields: ['name', 'postalAddress'],
887
-
888
- // Native Google Pay properties (available due to interface extension)
889
- type: 'CARD',
890
- parameters: {
891
- allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
892
- allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX']
893
- }
894
- };
777
+ // Required handler
778
+ button.onSuccess(handler); // Always required
779
+
780
+ // Recommended when shipping is enabled (auto-accepted if not registered)
781
+ button.onShippingAddressChange(handler);
782
+ button.onShippingOptionsChange(handler);
783
+
784
+ // Optional handlers with Promise support
785
+ button.onUnavailable(handler); // or await button.onUnavailable()
786
+ button.onError(handler); // or await button.onError()
787
+ button.onCancel(handler); // or await button.onCancel()
788
+
789
+ // Click handler with flow control
790
+ button.onClick(handler); // Return false to abort, or a Promise to defer
791
+
792
+ // Loaded handler
793
+ button.onLoaded(handler); // Notified when button renders
895
794
  ```
896
795
 
897
- **Important Notes**:
898
- - PayDock automatically handles the conversion and mapping between your configuration and the appropriate wallet APIs
899
- - The `tokenizationSpecification` property is omitted from the Google Pay interface extension as PayDock handles tokenization automatically
900
- - All properties shown are directly available in the `OpenWalletMeta` configuration object
796
+ ### Apple Pay-Specific Meta Properties
797
+
798
+ A full description of the [ApplePayOpenWalletMeta](#ApplePayOpenWalletMeta) properties:
799
+
800
+ **Required:**
801
+ - `amount`: The payment amount (number)
802
+ - `currency`: The currency code (string, e.g., "AUD")
803
+ - `country`: The country code (string, e.g., "AU")
804
+ - `amount_label`: Label for the total amount (string)
805
+ - `store_name`: Merchant store name (string)
806
+
807
+ **Optional:**
808
+ - `request_shipping?: boolean`: Enable shipping address collection
809
+ - `shipping_options?: IApplePayShippingOption[]`: Array of shipping options
810
+ - `show_billing_address?: boolean`: Show billing address fields
811
+ - `apple_pay_capabilities?: string[]`: Device capabilities
812
+ - `merchant_capabilities?: string[]`: Merchant capabilities
813
+ - `supported_networks?: string[]`: Supported payment networks
814
+ - `required_billing_contact_fields?: string[]`: Required billing contact fields
815
+ - `required_shipping_contact_fields?: string[]`: Required shipping contact fields
816
+ - `supported_countries?: string[]`: Supported countries
817
+ - `shipping_editing_mode?: 'available' | 'store_pickup'`: Shipping address editing mode
818
+ - `style?: { button_type?: ApplePayButtonType, button_style?: ApplePayButtonStyle }`: Button styling
819
+
820
+ ### Google Pay-Specific Meta Properties
821
+
822
+ A full description of the [GooglePayOpenWalletMeta](#GooglePayOpenWalletMeta) properties:
823
+
824
+ **Required:**
825
+ - `amount`: The payment amount (number)
826
+ - `currency`: The currency code (string, e.g., "AUD")
827
+ - `country`: The country code (string, e.g., "AU")
828
+
829
+ **Optional:**
830
+ - `amount_label?: string`: Label for the total amount
831
+ - `merchant_name?: string`: Display name for the merchant
832
+ - `request_shipping?: boolean`: Enable shipping address collection
833
+ - `shipping_options?: IGooglePayShippingOption[]`: Array of shipping options
834
+ - `show_billing_address?: boolean`: Show billing address fields
835
+ - `card_config?: GooglePayCardConfig`: Card configuration (auth methods, networks, tokenization)
836
+ - `style?: { button_type?: GooglePayButtonType, button_color?: GooglePayButtonColor, button_size_mode?: GooglePayButtonSizeMode }`: Button styling
901
837
 
902
- #### Shipping Options Format
838
+ ### Shipping Options Format
903
839
  ```javascript
904
840
  shipping_options: [
905
841
  {
@@ -907,12 +843,12 @@ shipping_options: [
907
843
  label: "Option Name", // Display name (string)
908
844
  detail: "Description", // Optional description (string)
909
845
  amount: 10.00, // Shipping cost as number
910
- date_components_range: { // Optional: delivery date range
846
+ date_components_range: { // Optional: delivery date range (Apple Pay only)
911
847
  start_date_components: {
912
- years: 0, // Years from now
913
- months: 0, // Months from now
914
- days: 5, // Days from now
915
- hours: 0, // Hours from now
848
+ years: 0,
849
+ months: 0,
850
+ days: 5,
851
+ hours: 0,
916
852
  },
917
853
  end_date_components: {
918
854
  years: 0,
@@ -925,263 +861,28 @@ shipping_options: [
925
861
  ]
926
862
  ```
927
863
 
928
- **Important**:
864
+ **Important**:
929
865
  - `amount` should be a **number**, not a string
930
- - `date_components_range` is optional but provides delivery estimates
866
+ - `date_components_range` is optional but provides delivery estimates (Apple Pay only)
931
867
  - Updated shipping options returned from event handlers don't require `date_components_range`
932
868
 
933
- #### Required Meta Fields Validation
934
-
935
- The `requiredMetaFields` parameter allows you to specify which fields in the meta object must be present. If any required field is missing, the constructor will throw an error:
936
-
937
- ```javascript
938
- // Example with validation
939
- const button = new paydock.OpenWalletButtons(
940
- '#widget',
941
- publicKeyOrAccessToken,
942
- serviceId,
943
- {
944
- amount: 100,
945
- currency: 'USD',
946
- // Missing amount_label will cause an error
947
- },
948
- ['amount', 'currency', 'amount_label'] // This will throw an error
949
- );
950
-
951
- // To avoid validation, pass an empty array or omit the parameter
952
- const button = new paydock.OpenWalletButtons(
953
- '#widget',
954
- publicKeyOrAccessToken,
955
- serviceId,
956
- meta,
957
- [] // No validation
958
- );
959
- ```
960
-
961
- ### Complete Test Setup Example
962
-
963
- Based on the actual test implementation, here's a complete working example for testing:
964
-
965
- ```html
966
- <!DOCTYPE html>
967
- <html lang="en">
968
- <head>
969
- <meta charset="UTF-8">
970
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
971
- <title>Open Wallet Apple Pay Test</title>
972
- </head>
973
- <body>
974
- <h1>Apple Pay Test Page</h1>
975
- <table>
976
- <tr>
977
- <td>Service ID:</td>
978
- <td><input type="text" id="service_id" placeholder="Enter your service ID" /></td>
979
- </tr>
980
- <tr>
981
- <td>Access Token/Public Key:</td>
982
- <td><input type="text" id="access_token" placeholder="Enter your access token" /></td>
983
- </tr>
984
- </table>
985
- <button onclick="loadApplePayButton()">Load Apple Pay Button</button>
986
- <div id="widget"></div>
987
-
988
- <script src="https://widget.paydock.com/sdk/latest/widget.umd.min.js"></script>
989
- <script>
990
- function loadApplePayButton() {
991
- const shippingOptions = [
992
- {
993
- label: "Standard Shipping",
994
- detail: "Arrives in 5-7 business days",
995
- amount: 10,
996
- id: "standard",
997
- date_components_range: {
998
- start_date_components: { years: 0, months: 0, days: 5, hours: 0 },
999
- end_date_components: { years: 0, months: 0, days: 7, hours: 0 }
1000
- }
1001
- },
1002
- {
1003
- label: "Express Shipping",
1004
- detail: "Arrives in 1-2 business days",
1005
- amount: 20,
1006
- id: "express",
1007
- date_components_range: {
1008
- start_date_components: { years: 0, months: 0, days: 1, hours: 0 },
1009
- end_date_components: { years: 0, months: 0, days: 2, hours: 0 }
1010
- }
1011
- }
1012
- ];
1013
-
1014
- const widget = new paydock.OpenWalletButtons(
1015
- '#widget',
1016
- document.getElementById("access_token").value,
1017
- document.getElementById("service_id").value,
1018
- {
1019
- amount: 100,
1020
- currency: 'USD',
1021
- country: 'US',
1022
- amount_label: 'Total',
1023
- apple_pay_capabilities: [
1024
- 'credentials_available',
1025
- 'credentials_status_unknown',
1026
- 'credentials_unavailable'
1027
- ],
1028
- shipping_options: shippingOptions,
1029
- request_shipping: true,
1030
-
1031
- // Extended Apple Pay properties (native interface)
1032
- merchantCapabilities: [
1033
- 'supports3DS',
1034
- 'supportsCredit',
1035
- 'supportsDebit'
1036
- ],
1037
- supportedNetworks: [
1038
- 'visa',
1039
- 'masterCard',
1040
- 'amex',
1041
- 'discover'
1042
- ],
1043
- requiredBillingContactFields: [
1044
- 'name',
1045
- 'postalAddress'
1046
- ],
1047
- requiredShippingContactFields: [
1048
- 'postalAddress',
1049
- 'name',
1050
- 'phone',
1051
- 'email'
1052
- ]
1053
- },
1054
- ['amount_label', 'country', 'request_shipping', 'shipping_options', 'apple_pay_capabilities']
1055
- );
1056
-
1057
- // Required handlers
1058
- widget.onSuccess(async function (data) {
1059
- console.log("Payment successful:", data);
1060
- // Process the OTT token
1061
- alert(`Payment successful! OTT Token: ${data.token}`);
1062
- });
1063
-
1064
- widget.onShippingAddressChange(async function (data) {
1065
- console.log("Shipping address changed:", data);
1066
-
1067
- // Simulate updated shipping options based on address
1068
- const updatedOptions = [
1069
- { label: "Local Delivery", detail: "Same day delivery", amount: 5, id: "local" },
1070
- { label: "Regional Delivery", detail: "Next day delivery", amount: 15, id: "regional" }
1071
- ];
1072
-
1073
- return {
1074
- amount: 100 + updatedOptions[0].amount,
1075
- shipping_options: updatedOptions
1076
- };
1077
- });
1078
-
1079
- widget.onShippingOptionsChange(async function (data) {
1080
- console.log("Shipping option changed:", data);
1081
-
1082
- // Note: Check your actual data structure - might be data.data.amount
1083
- const shippingCost = data.amount || data.data?.amount || 0;
1084
- return {
1085
- amount: 100 + shippingCost
1086
- };
1087
- });
1088
-
1089
- // Optional handlers
1090
- widget.onError(function (data) {
1091
- console.error("Payment error:", data);
1092
- alert("Payment failed: " + data.error.message);
1093
- });
1094
-
1095
- widget.onCancel(function (data) {
1096
- console.log("Payment cancelled:", data);
1097
- alert("Payment was cancelled");
1098
- });
1099
-
1100
- widget.onClick(function (data) {
1101
- console.log("Apple Pay button clicked:", data);
1102
- // Optional: Add validation logic here
1103
- });
1104
-
1105
- widget.setEnv('sandbox');
1106
- widget.load();
1107
- }
1108
- </script>
1109
- </body>
1110
- </html>
1111
- ```
1112
-
1113
- ### Common Issues and Troubleshooting
1114
-
1115
- #### Event Data Structure Variations
1116
- Different implementations might return data in slightly different structures. Always check the actual data structure in your console:
1117
-
1118
- ```javascript
1119
- // In your event handlers, log the data to see the actual structure
1120
- widget.onShippingOptionsChange(async function (data) {
1121
- console.log("Full data object:", data);
1122
-
1123
- // Try different access patterns based on your implementation
1124
- const amount = data.amount || // Direct access
1125
- data.data?.amount || // Nested in data property
1126
- data.shippingCost || // Alternative property name
1127
- 0; // Fallback
1128
-
1129
- return { amount: baseAmount + amount };
1130
- });
1131
- ```
1132
-
1133
- #### Required vs Optional Configuration
1134
- ```javascript
1135
- // Minimal required configuration
1136
- const minimalConfig = {
1137
- amount: 100,
1138
- currency: 'USD'
1139
- };
1140
-
1141
- // Recommended configuration with validation
1142
- const recommendedConfig = {
1143
- amount: 100,
1144
- currency: 'USD',
1145
- amount_label: 'Total',
1146
- country: 'US',
1147
- apple_pay_capabilities: ['credentials_available']
1148
- };
1149
-
1150
- // Full configuration with shipping
1151
- const fullConfig = {
1152
- amount: 100,
1153
- currency: 'USD',
1154
- amount_label: 'Total',
1155
- country: 'US',
1156
- request_shipping: true,
1157
- shipping_options: [...],
1158
- apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown', 'credentials_unavailable']
1159
- };
1160
- ```
1161
-
1162
- #### Environment Setup
869
+ ### Environment Setup
1163
870
  ```javascript
1164
871
  // Always set environment before loading
1165
- widget.setEnv('sandbox');
1166
- widget.load();
872
+ button.setEnv('sandbox');
873
+ button.load();
1167
874
  ```
1168
875
 
1169
- #### Error Handling Best Practices
876
+ ### Error Handling Best Practices
1170
877
  ```javascript
1171
- widget.onError(function(data) {
878
+ button.onError(function({ data }) {
1172
879
  console.error('Full error object:', data);
1173
-
1174
- // Check different error properties
1175
- const errorMessage = data.error?.message ||
1176
- data.message ||
1177
- 'Unknown error occurred';
1178
-
1179
- // Handle different error types
880
+
881
+ const errorMessage = data.error?.message || 'Unknown error occurred';
882
+
1180
883
  if (data.context?.operation === 'wallet_operation') {
1181
- // Handle wallet-specific errors
1182
884
  showWalletError(errorMessage);
1183
885
  } else {
1184
- // Handle general errors
1185
886
  showGeneralError(errorMessage);
1186
887
  }
1187
888
  });