@paydock/client-sdk 1.144.1-beta → 1.147.0

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 (82) hide show
  1. package/README.md +551 -32
  2. package/bundles/index.cjs +2683 -599
  3. package/bundles/index.cjs.d.ts +322 -21
  4. package/bundles/index.mjs +2683 -600
  5. package/bundles/index.mjs.d.ts +322 -21
  6. package/bundles/types/api/api-base.d.ts +6 -0
  7. package/bundles/types/api/api-base.d.ts.map +1 -1
  8. package/bundles/types/api/api-charge-internal.d.ts +1 -5
  9. package/bundles/types/api/api-charge-internal.d.ts.map +1 -1
  10. package/bundles/types/canvas-3ds/canvas-3ds-event-map.d.ts +50 -0
  11. package/bundles/types/canvas-3ds/canvas-3ds-event-map.d.ts.map +1 -1
  12. package/bundles/types/canvas-3ds/canvas-3ds.d.ts +7 -5
  13. package/bundles/types/canvas-3ds/canvas-3ds.d.ts.map +1 -1
  14. package/bundles/types/canvas-3ds/index.d.ts +1 -1
  15. package/bundles/types/canvas-3ds/index.d.ts.map +1 -1
  16. package/bundles/types/canvas-3ds/services/gpayments-service.d.ts +117 -2
  17. package/bundles/types/canvas-3ds/services/gpayments-service.d.ts.map +1 -1
  18. package/bundles/types/canvas-3ds/services/standalone3ds-service.d.ts +6 -0
  19. package/bundles/types/canvas-3ds/services/standalone3ds-service.d.ts.map +1 -1
  20. package/bundles/types/components/iframe-event.d.ts +4 -3
  21. package/bundles/types/components/iframe-event.d.ts.map +1 -1
  22. package/bundles/types/components/iframe.d.ts +5 -0
  23. package/bundles/types/components/iframe.d.ts.map +1 -1
  24. package/bundles/types/components/param.d.ts +19 -0
  25. package/bundles/types/components/param.d.ts.map +1 -1
  26. package/bundles/types/helper/browser.d.ts.map +1 -1
  27. package/bundles/types/helper/element-id.d.ts +3 -1
  28. package/bundles/types/helper/element-id.d.ts.map +1 -1
  29. package/bundles/types/helper/uuid.d.ts.map +1 -1
  30. package/bundles/types/index-cba.d.ts +1 -1
  31. package/bundles/types/index-cba.d.ts.map +1 -1
  32. package/bundles/types/index.d.ts +2 -2
  33. package/bundles/types/index.d.ts.map +1 -1
  34. package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts +41 -0
  35. package/bundles/types/open-wallets/apple-pay-open-wallet-button.d.ts.map +1 -1
  36. package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts +10 -0
  37. package/bundles/types/open-wallets/base/open-wallet-buttons.d.ts.map +1 -1
  38. package/bundles/types/open-wallets/base/service-config-cache.d.ts +23 -0
  39. package/bundles/types/open-wallets/base/service-config-cache.d.ts.map +1 -0
  40. package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts +33 -1
  41. package/bundles/types/open-wallets/google-pay-open-wallet-button.d.ts.map +1 -1
  42. package/bundles/types/open-wallets/index.d.ts +82 -1
  43. package/bundles/types/open-wallets/index.d.ts.map +1 -1
  44. package/bundles/types/open-wallets/interfaces/apple-pay/apple-pay-availability.interface.d.ts +41 -0
  45. package/bundles/types/open-wallets/interfaces/apple-pay/apple-pay-availability.interface.d.ts.map +1 -0
  46. package/bundles/types/open-wallets/interfaces/apple-pay/index.d.ts +1 -0
  47. package/bundles/types/open-wallets/interfaces/apple-pay/index.d.ts.map +1 -1
  48. package/bundles/types/open-wallets/interfaces/google-pay/google-pay-availability.interface.d.ts +25 -0
  49. package/bundles/types/open-wallets/interfaces/google-pay/google-pay-availability.interface.d.ts.map +1 -0
  50. package/bundles/types/open-wallets/interfaces/google-pay/index.d.ts +1 -0
  51. package/bundles/types/open-wallets/interfaces/google-pay/index.d.ts.map +1 -1
  52. package/bundles/types/open-wallets/interfaces/index.d.ts +3 -0
  53. package/bundles/types/open-wallets/interfaces/index.d.ts.map +1 -1
  54. package/bundles/types/open-wallets/interfaces/open-wallet-availability.interface.d.ts +31 -0
  55. package/bundles/types/open-wallets/interfaces/open-wallet-availability.interface.d.ts.map +1 -0
  56. package/bundles/types/open-wallets/services/apple-pay/apple-pay-availability.d.ts +58 -0
  57. package/bundles/types/open-wallets/services/apple-pay/apple-pay-availability.d.ts.map +1 -0
  58. package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts +8 -10
  59. package/bundles/types/open-wallets/services/apple-pay/apple-pay.open-wallet.service.d.ts.map +1 -1
  60. package/bundles/types/open-wallets/services/apple-pay/index.d.ts +1 -0
  61. package/bundles/types/open-wallets/services/apple-pay/index.d.ts.map +1 -1
  62. package/bundles/types/open-wallets/services/google-pay/google-pay-availability.d.ts +53 -0
  63. package/bundles/types/open-wallets/services/google-pay/google-pay-availability.d.ts.map +1 -0
  64. package/bundles/types/open-wallets/services/google-pay/google-pay.open-wallet.service.d.ts.map +1 -1
  65. package/bundles/types/open-wallets/services/google-pay/index.d.ts +1 -0
  66. package/bundles/types/open-wallets/services/google-pay/index.d.ts.map +1 -1
  67. package/bundles/types/widget/multi-widget.d.ts +19 -0
  68. package/bundles/types/widget/multi-widget.d.ts.map +1 -1
  69. package/bundles/widget.umd.js +2683 -599
  70. package/bundles/widget.umd.js.d.ts +322 -21
  71. package/bundles/widget.umd.js.min.d.ts +322 -21
  72. package/bundles/widget.umd.min.js +1 -1
  73. package/docs/api-canvas3ds.md +10 -8
  74. package/docs/api-checkout-button.md +15 -0
  75. package/docs/api-ps-widget.md +15 -0
  76. package/docs/api-widget.md +15 -0
  77. package/docs/canvas3ds-examples.md +43 -1
  78. package/docs/open-wallet-buttons-examples.md +170 -2
  79. package/docs/open-wallet-buttons.md +252 -29
  80. package/docs/widget-examples.md +41 -0
  81. package/package.json +20 -11
  82. package/slate.md +254 -3
package/slate.md CHANGED
@@ -194,8 +194,48 @@ widget.setRefId('id'); // your unique identifier to identify the data
194
194
  widget.setFormFields(['phone', 'email']); // add additional fields for form of widget
195
195
 
196
196
  widget.setSupportedCardIcons(['mastercard', 'visa']); // add icons of supported card types
197
+
198
+ widget.setAllowedCardSchemes(['mastercard', 'visa']); // restrict which card schemes the card number field accepts
199
+ ```
200
+
201
+ ### Restricting accepted card schemes
202
+
203
+ `setAllowedCardSchemes(schemes)` restricts which card schemes the card number field accepts, **without** changing
204
+ which card icons the widget displays. Call it before `load()`.
205
+
206
+ ```javascript
207
+ widget.setAllowedCardSchemes(['visa', 'mastercard']);
197
208
  ```
198
209
 
210
+ Accepted identifiers — the schemes the widget can resolve from a card number:
211
+
212
+ `amex`, `ausbc`, `diners`, `discover`, `eftpos`, `japcb`, `mastercard`, `solo`, `unionpay`, `visa`
213
+
214
+ Behaviour:
215
+
216
+ - **Not called, or an empty array** — every scheme is accepted. Existing integrations are unaffected.
217
+ - **Case-insensitive**, and surrounding whitespace is ignored: `' Visa '` and `'MASTERCARD'` both work. Note that
218
+ `setSupportedCardIcons` matches case-**sensitively**; the two methods differ here.
219
+ - **Unsupported identifiers are ignored with a `console.warn`** naming the value, and never throw. A list in which
220
+ every identifier is unsupported therefore applies **no restriction at all** — check the console if a restriction
221
+ seems to have no effect. The icon-only values `visa_white` and `eftpos_white` are not schemes and are rejected,
222
+ as are `laser` and `maestro`, which the widget can never resolve from a card number.
223
+ - **Takes precedence over `setSupportedCardIcons`.** When a non-empty list is supplied here, it is the only list
224
+ used for validation, and the second argument of `setSupportedCardIcons` no longer affects validation. Icons keep
225
+ coming from `setSupportedCardIcons`, so a scheme can legitimately be shown as an icon and still be rejected —
226
+ make sure that is what you intend:
227
+
228
+ ```javascript
229
+ widget.setSupportedCardIcons(['visa', 'mastercard', 'amex'], true);
230
+ widget.setAllowedCardSchemes(['visa', 'mastercard']);
231
+ // three icons are displayed; an Amex card is rejected
232
+ ```
233
+
234
+ - **Calling it again replaces the previous list** rather than merging with it.
235
+ - A card of a rejected scheme shows `Card type not accepted.` on the card number field, the submit button is
236
+ disabled, and the submit handler refuses the card even if the button is re-enabled outside the widget. The same
237
+ message is shown for a card whose scheme cannot be resolved at all.
238
+
199
239
  This example shows how you can use a lot of other methods to settings your form
200
240
 
201
241
  ### Error handling
@@ -355,6 +395,7 @@ When handling errors, consider:
355
395
  var widget = new paydock.HtmlWidget('#widget', 'publicKey', 'gatewayId');
356
396
 
357
397
  widget.setSupportedCardIcons(['mastercard', 'visa']);
398
+ widget.setAllowedCardSchemes(['mastercard', 'visa']);
358
399
  widget.setFormFields(['phone', 'email']);
359
400
  widget.setRefId('custom-ref-id');
360
401
  widget.onFinishInsert('input[name="payment_source_token"]', 'payment_source');
@@ -743,7 +784,13 @@ After you initialized the standalone 3ds charge via `v1/charges/standalone-3ds`
743
784
  console.log(data);
744
785
  });
745
786
  canvas3ds.on("chargeAuthChallenge", function (data) {
746
- console.log(data);
787
+ console.log(data); // keep your loader up — the challenge page is still loading
788
+ });
789
+ canvas3ds.on("chargeAuthChallengeLoaded", function (data) {
790
+ console.log(data.reason); // 'load' | 'timeout' — hide your loader, the challenge is visible
791
+ });
792
+ canvas3ds.on("chargeAuthChallengeCompleted", function (data) {
793
+ console.log(data.source); // 'poll' | 'callback' — shopper finished, cover the challenge with "Completing verification"
747
794
  });
748
795
  canvas3ds.on("chargeAuthDecoupled", function (data) {
749
796
  console.log(data.result.description);
@@ -766,10 +813,26 @@ After you initialized the standalone 3ds charge via `v1/charges/standalone-3ds`
766
813
  - A `data.status` of `rejected` will be received when the authorization was rejected.
767
814
  - A `data.status` of `invalid_event` will be received for unhandled situations.
768
815
  - The `chargeAuthChallenge` event is sent before starting a challenge flow (i.e. opening an IFrame for the customer to complete a challenge with ther bank). Once the end customer performs the challenge, the Canvas3ds will be able to identify the challenge result and will either produce a `chargeAuthSuccess` or `chargeAuthReject` event.
816
+ - The `chargeAuthChallengeLoaded` event (SDK **v1.147.0+**) is sent once per challenge, after `chargeAuthChallenge`, when the challenge IFrame has finished loading the bank's page (its first `load` event) — this is the moment the customer can actually see the challenge. `data.reason` is `load` for a real load, or `timeout` when no load was observed within 2.5 seconds: the event is emitted anyway so you never hold a loading indicator forever (a `load` arriving later is simply ignored). Hide your loader on this event either way; `data.reason` is only informational (e.g. analytics). Not sent for decoupled challenges (no challenge IFrame).
817
+ - The `chargeAuthChallengeCompleted` event (SDK **v1.147.0+**) is sent once the customer has finished the challenge (or approved a decoupled authentication): the bank has delivered the final result to the 3DS server and the Canvas3ds is now obtaining the outcome. Whatever the bank or the 3DS server render inside the IFrame from here on is plumbing, not UX — cover the IFrame with your own "Completing verification" state and hold it until the terminal event. `data.source` tells you how the SDK learned about it: `poll` (the 3DS server's result monitor — the usual case, it flips before the IFrame has even left the bank's page) or `callback` (the callback message carrying the outcome arrived first; the terminal event follows immediately) — handle both the same way. Sent at most once per authentication, always before `chargeAuthSuccess` / `chargeAuthReject` / `error` and never after them. A wrong OTP or a further interactive step (e.g. a second OTP screen) does **not** send it — no result has been delivered yet — so no grace timer or reveal fallback is needed on your side. Also sent for decoupled challenges.
769
818
  - The `chargeAuthDecoupled` event is sent when the flow is a decoupled challenge, alongside a `data.result.description` field that you must show to the customer, indicating the method the user must use to authenticate. For example this may happen by having the cardholder authenticating directly with their banking app through biometrics. Once the end customer does this, the Canvas3ds will be able to recognize the challenge result is ready and will either produce a `chargeAuthSuccess` or `chargeAuthReject` event.
770
819
  - The `error` event is sent if an unexpected issue with the client library occurs. In such scenarios, you should consider the autentication process as interrupted:
771
820
  - When getting this event, you will get on `data.error` the full error object.
772
821
 
822
+ ### Recommended loading indicator pattern
823
+
824
+ > Requires SDK **v1.147.0 or later** (`chargeAuthChallengeLoaded` / `chargeAuthChallengeCompleted`). On older versions the same effect needs a `MutationObserver` on the container plus `load` listeners on the challenge IFrame — see the Standalone 3DS UX guide in the playground for that legacy approach.
825
+
826
+ The Canvas3ds renders nothing visible until a challenge is presented, and `chargeAuthChallenge` fires when the API responds — about 1–2 seconds before the bank's page actually paints inside the IFrame. Drive a single loading indicator from the events:
827
+
828
+ 1. Show the loader **before** you `POST /v1/charges/standalone-3ds` and keep it up through `canvas3ds.load()` (fingerprinting and processing are invisible).
829
+ 2. Keep it up on `chargeAuthChallenge` — the challenge IFrame is being injected but is still blank.
830
+ 3. Hide it on `chargeAuthChallengeLoaded` — the challenge is visible. `data.reason` tells you whether it was a real paint (`load`) or the 2.5 s safety fallback (`timeout`); either way, no further handling is needed.
831
+ 4. Cover the IFrame with a "Completing verification" indicator on `chargeAuthChallengeCompleted` — the customer finished the challenge and the SDK is obtaining the outcome — and hold it until the terminal event. No grace timer or reveal fallback is needed: a wrong OTP or a second interactive step does not fire this event.
832
+ 5. Finish on `chargeAuthSuccess` / `chargeAuthReject` / `error`.
833
+
834
+ Decoupled challenges (`chargeAuthDecoupled`) never emit `chargeAuthChallengeLoaded` (there is no challenge IFrame) but do emit `chargeAuthChallengeCompleted` once the customer approved out-of-band: show a dedicated waiting state with `data.result.description` until then, and "Completing verification" until the terminal event. Frictionless flows go straight from `load()` to the terminal event.
835
+
773
836
  ### Events and Values
774
837
 
775
838
  | Event Value | Type | Description |
@@ -777,6 +840,8 @@ After you initialized the standalone 3ds charge via `v1/charges/standalone-3ds`
777
840
  | <code>chargeAuthSuccess</code> | <code>object</code> | Instance of [ChargeEventResponse](#cb_chargeEventResponse) |
778
841
  | <code>chargeAuthReject</code> | <code>object</code> | Instance of [ChargeEventResponse](#cb_chargeEventResponse) |
779
842
  | <code>chargeAuthChallenge</code> | <code>object</code> | Instance of [ChargeEventResponse](#cb_chargeEventResponse) |
843
+ | <code>chargeAuthChallengeLoaded</code> | <code>object</code> | Instance of [ChallengeLoadedResponse](#cb_challengeLoadedResponse) |
844
+ | <code>chargeAuthChallengeCompleted</code> | <code>object</code> | Instance of [ChallengeCompletedResponse](#cb_challengeCompletedResponse) |
780
845
  | <code>chargeAuthDecoupled</code> | <code>object</code> | Instance of [ChargeEventResponse](#cb_chargeEventResponse) |
781
846
  | <code>chargeAuthInfo</code> | <code>object</code> | Instance of [ChargeEventResponse](#cb_chargeEventResponse) |
782
847
  | <code>error</code> | <code>object</code> | Instance of [chargeError](#cb_chargeError) |
@@ -794,6 +859,24 @@ After you initialized the standalone 3ds charge via `v1/charges/standalone-3ds`
794
859
  | <code>info</code> | <code>string</code> | info field for `chargeAuthInfo` event |
795
860
  | <code>result.description</code> | <code>string</code> [Optional] | field that you must show to the customer, indicating the method the user must use to authenticate during the decoupled challenge flow. |
796
861
 
862
+ <a name="cb_challengeLoadedResponse" id="cb_challengeLoadedResponse"></a>
863
+
864
+ ### ChallengeLoadedResponse
865
+
866
+ | Param | Type | Description |
867
+ | ------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------- |
868
+ | <code>charge_3ds_id</code> | <code>string</code> | Universal unique transaction identifier to identify the transaction |
869
+ | <code>reason</code> | <code>string</code> | `load` — the challenge IFrame fired its first load event; `timeout` — no load within 2.5 s, emitted so a loader is never held forever (a later load is ignored) |
870
+
871
+ <a name="cb_challengeCompletedResponse" id="cb_challengeCompletedResponse"></a>
872
+
873
+ ### ChallengeCompletedResponse
874
+
875
+ | Param | Type | Description |
876
+ | ------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------- |
877
+ | <code>charge_3ds_id</code> | <code>string</code> | Universal unique transaction identifier to identify the transaction |
878
+ | <code>source</code> | <code>string</code> | `poll` — the 3DS server's result monitor reported that the bank delivered the result (the usual case); `callback` — the callback message carrying the outcome arrived first (the terminal event follows immediately). Informational only — handle both the same way |
879
+
797
880
  ### ChargeError
798
881
 
799
882
  <a name="cb_chargeError" id="cb_chargeError"></a>
@@ -2147,6 +2230,106 @@ Bear in mind that you must set an environment before calling `button.load()`.
2147
2230
  button.setEnv('sandbox');
2148
2231
  ```
2149
2232
 
2233
+ ### Checking availability before instantiation (static)
2234
+
2235
+ `ApplePayOpenWalletButton.checkAvailability(options)` is a **static** method so you can decide
2236
+ whether to show an Apple Pay option — or which payment method to default to — **without
2237
+ instantiating the button** and waiting for the `onUnavailable` event.
2238
+
2239
+ > **Apple Pay is no longer Safari-only.** Since iOS 16 (third-party mobile browsers) and the
2240
+ > iOS 18 / 2025 desktop rollout, Apple Pay also works in Chrome, Edge and Firefox — including
2241
+ > on Windows — via a **cross-device QR handoff**: the user scans a code and completes the
2242
+ > payment on their iPhone. Because the paying device is often *not* the browsing device, the
2243
+ > only authoritative availability signal is the async `checkAvailability()`.
2244
+ > `applePayCapabilities()` is what Apple recommends; `canMakePayments()` is just a coarse
2245
+ > local-device hint. See
2246
+ > [Apple — Checking for Apple Pay availability](https://developer.apple.com/documentation/applepayontheweb/checking-for-apple-pay-availability).
2247
+
2248
+ #### `ApplePayOpenWalletButton.checkAvailability(options)`
2249
+
2250
+ The single, authoritative, cross-browser-aware check. It resolves the merchant identifier,
2251
+ loads Apple's web SDK if needed, and queries `ApplePaySession.applePayCapabilities()`.
2252
+
2253
+ You may supply the merchant context in either of two ways:
2254
+
2255
+ ```javascript
2256
+ // 1) Lightest path — no network — when you already know the Apple merchant identifier:
2257
+ const result = await paydock.ApplePayOpenWalletButton.checkAvailability({
2258
+ merchant_id: 'merchant.com.example',
2259
+ });
2260
+
2261
+ // 2) Resolve the merchant identifier from the service configuration (fetched & cached):
2262
+ const result = await paydock.ApplePayOpenWalletButton.checkAvailability({
2263
+ public_key_or_access_token: publicKeyOrAccessToken,
2264
+ service_id: serviceId,
2265
+ env: 'sandbox',
2266
+ // Optional — which device statuses count as "available".
2267
+ // Defaults to ['credentials_available', 'credentials_status_unknown'].
2268
+ apple_pay_capabilities: ['credentials_available', 'credentials_status_unknown'],
2269
+ });
2270
+ ```
2271
+
2272
+ **Result shape (`ApplePayAvailabilityResult`):**
2273
+
2274
+ ```javascript
2275
+ {
2276
+ available: true, // verdict vs the allowed capability set
2277
+ supported: true, // Apple Pay usable here AT ALL (incl. cross-device QR)
2278
+ has_native_session: false, // native same-device session present (canMakePayments)
2279
+ payment_credential_status: // OUTPUT — the device's reported status
2280
+ 'paymentCredentialStatusUnknown',
2281
+ reason: undefined, // set when not available, see below
2282
+ }
2283
+ ```
2284
+
2285
+ **Inferring the transport (Apple does not expose it directly):**
2286
+ - `available && has_native_session` ⇒ **native** Apple Pay sheet is likely (Safari on an Apple device).
2287
+ - `available && !has_native_session` ⇒ **cross-device / QR** handoff is likely (e.g. Chrome on desktop).
2288
+
2289
+ `payment_credential_status` is the device's actual status:
2290
+ `'paymentCredentialsAvailable'`, `'paymentCredentialStatusUnknown'`,
2291
+ `'paymentCredentialsUnavailable'`, or `'applePayUnsupported'`. **Third-party / desktop
2292
+ browsers normally report `paymentCredentialStatusUnknown`** (Apple can't see the remote
2293
+ iPhone's cards until the user scans the QR), which is why the default allowed set includes it.
2294
+
2295
+ The `apple_pay_capabilities` **input** maps to those statuses
2296
+ (`credentials_available` → `paymentCredentialsAvailable`,
2297
+ `credentials_status_unknown` → `paymentCredentialStatusUnknown`,
2298
+ `credentials_unavailable` → `paymentCredentialsUnavailable`) and decides which ones make
2299
+ `available` true. When omitted, **both** `paymentCredentialsAvailable` and
2300
+ `paymentCredentialStatusUnknown` count — narrow it to `['credentials_available']` only if you
2301
+ want to require a confirmed local card (this will hide the button in cross-browser/QR contexts).
2302
+
2303
+ When `available` is `false`, `reason` is one of: `'unsupported_browser'`,
2304
+ `'missing_merchant_id'`, `'service_type_mismatch'`, `'config_fetch_failed'`,
2305
+ `'sdk_load_failed'`, `'query_failed'`, `'no_credentials'`, or `'no_native_session'`
2306
+ (only from the synchronous check below).
2307
+
2308
+ ```javascript
2309
+ const result = await paydock.ApplePayOpenWalletButton.checkAvailability({ merchant_id: merchantId });
2310
+ if (result.available) {
2311
+ renderApplePayButton();
2312
+ } else {
2313
+ console.log('Apple Pay unavailable:', result.reason, result.payment_credential_status);
2314
+ }
2315
+ ```
2316
+
2317
+ **Synchronous native-only fast check (`sync: true`).** Pass `{ sync: true }` for a cheap,
2318
+ network-free pre-check that resolves immediately — it runs only the native same-device check
2319
+ (`window.ApplePaySession` + `canMakePayments()`), with no merchant resolution, SDK load, or
2320
+ `applePayCapabilities()` query. In this mode `available` reflects the native session only and
2321
+ `payment_credential_status` is `undefined`. It is a Safari-oriented hint and is **not**
2322
+ authoritative for cross-browser / QR availability (which require the full async check above).
2323
+
2324
+ ```javascript
2325
+ const { has_native_session } = await paydock.ApplePayOpenWalletButton.checkAvailability({
2326
+ sync: true,
2327
+ });
2328
+ if (has_native_session) {
2329
+ // Native Apple Pay is ready on this device (Safari fast path).
2330
+ }
2331
+ ```
2332
+
2150
2333
  ### Full Apple Pay example
2151
2334
 
2152
2335
  ```html
@@ -2565,6 +2748,58 @@ The GooglePayOpenWalletButton constructor accepts the following parameters:
2565
2748
 
2566
2749
  > **Note:** Required meta fields (`amount`, `currency`, `country`) are validated automatically by the `GooglePayOpenWalletButton` class. You do not need to specify them manually.
2567
2750
 
2751
+ ### Checking availability before instantiation (static)
2752
+
2753
+ `GooglePayOpenWalletButton.checkAvailability(options)` is a **static** method that reports
2754
+ whether Google Pay can be used in the current context **without instantiating the button**.
2755
+ It loads the Google Pay JS SDK if needed and runs `PaymentsClient.isReadyToPay()`.
2756
+
2757
+ Unlike Apple Pay, **all options are optional** — Google Pay's readiness check does not
2758
+ require a merchant identifier. Supplying `publicKeyOrAccessToken` + `serviceId` additionally
2759
+ validates that the service is a Google Pay service (and resolves the merchant id).
2760
+
2761
+ ```javascript
2762
+ // Simplest form — no merchant context needed:
2763
+ const result = await paydock.GooglePayOpenWalletButton.checkAvailability();
2764
+
2765
+ // Or validate the service is a Google Pay service while checking:
2766
+ const result = await paydock.GooglePayOpenWalletButton.checkAvailability({
2767
+ public_key_or_access_token: publicKeyOrAccessToken,
2768
+ service_id: serviceId,
2769
+ env: 'sandbox',
2770
+ });
2771
+ ```
2772
+
2773
+ **Result shape (`GooglePayAvailabilityResult`):**
2774
+
2775
+ ```javascript
2776
+ {
2777
+ available: true, // isReadyToPay().result — ready to pay in this context
2778
+ supported: true, // the Google Pay JS API is present and the query ran
2779
+ payment_method_present: true, // OUTPUT — whether the buyer already has a usable card
2780
+ reason: undefined, // set when not available, see below
2781
+ }
2782
+ ```
2783
+
2784
+ > **Note:** the static check uses the **default** card configuration (standard auth methods
2785
+ > and card networks). A button instance configured with a custom `card_config` may produce a
2786
+ > different result.
2787
+
2788
+ When `available` is `false`, `reason` is one of: `'unsupported_browser'`,
2789
+ `'service_type_mismatch'`, `'config_fetch_failed'`, `'sdk_load_failed'`, `'query_failed'`,
2790
+ `'no_payment_method'`, or `'api_not_loaded'` (only from the synchronous check below).
2791
+
2792
+ **Synchronous fast check (`sync: true`).** Google Pay has no synchronous device/card
2793
+ capability API, so `{ sync: true }` only reports whether the Google Pay JS API is already
2794
+ present in the page — it does **not** run `isReadyToPay()`:
2795
+
2796
+ ```javascript
2797
+ const { available } = await paydock.GooglePayOpenWalletButton.checkAvailability({
2798
+ sync: true,
2799
+ });
2800
+ // `available` here means "the Google Pay JS API script is loaded", not "ready to pay".
2801
+ ```
2802
+
2568
2803
  ### Full Google Pay Example
2569
2804
 
2570
2805
  ```html
@@ -2707,12 +2942,28 @@ Both `ApplePayOpenWalletButton` and `GooglePayOpenWalletButton` share the same e
2707
2942
 
2708
2943
  ### Checking for button availability
2709
2944
 
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.
2945
+ There are two ways to know whether a wallet is available:
2946
+
2947
+ **1. After `load()` — the `onUnavailable()` callback.** 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
2948
 
2712
2949
  ```javascript
2713
2950
  button.onUnavailable(({ data }) => console.log("No wallet button available", data));
2714
2951
  ```
2715
2952
 
2953
+ **2. Before instantiation — the static `checkAvailability()` method.** Each button class exposes a static `checkAvailability(options)` that resolves availability **without instantiating the button**, so you can decide whether to render a wallet option (or which payment method to default to) up front. The options and result are wallet-specific — see [Apple Pay → Checking availability before instantiation](#checking-availability-before-instantiation-static) and [Google Pay → Checking availability before instantiation](#checking-availability-before-instantiation-static-1).
2954
+
2955
+ ```javascript
2956
+ // Apple Pay
2957
+ const apple = await paydock.ApplePayOpenWalletButton.checkAvailability({ merchant_id: merchantId });
2958
+
2959
+ // Google Pay (merchant context optional)
2960
+ const google = await paydock.GooglePayOpenWalletButton.checkAvailability();
2961
+
2962
+ if (apple.available || google.available) {
2963
+ // Show a wallet payment option.
2964
+ }
2965
+ ```
2966
+
2716
2967
  ### Service type validation
2717
2968
 
2718
2969
  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`:
@@ -2874,7 +3125,7 @@ A full description of the [ApplePayOpenWalletMeta](#ApplePayOpenWalletMeta) prop
2874
3125
  - `request_shipping?: boolean`: Enable shipping address collection
2875
3126
  - `shipping_options?: IApplePayShippingOption[]`: Array of shipping options
2876
3127
  - `show_billing_address?: boolean`: Show billing address fields
2877
- - `apple_pay_capabilities?: string[]`: Device capabilities
3128
+ - `apple_pay_capabilities?: string[]`: Device credential statuses that make the button render. **Defaults to `['credentials_available', 'credentials_status_unknown']`**: `credentials_available` means the device has a confirmed Apple Pay card ready to use; `credentials_status_unknown` means a local card can't be confirmed but Apple Pay can still proceed (e.g. the cross-device QR flow used by Chrome, Edge and Firefox). Narrow to `['credentials_available']` to require a confirmed local card.
2878
3129
  - `merchant_capabilities?: string[]`: Merchant capabilities
2879
3130
  - `supported_networks?: string[]`: Supported payment networks
2880
3131
  - `required_billing_contact_fields?: string[]`: Required billing contact fields