@agent-cards/checkout 0.5.0 → 0.7.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.
- package/CHANGELOG.md +17 -0
- package/README.md +49 -31
- package/dist/attachment.d.ts +11 -0
- package/dist/attachment.js +50 -0
- package/dist/braintree.d.ts +2 -0
- package/dist/braintree.js +12 -0
- package/dist/cdp.d.ts +21 -7
- package/dist/cdp.js +313 -159
- package/dist/client.d.ts +113 -25
- package/dist/client.js +134 -22
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/preparation.js +5 -4
- package/dist/prepared-processor.d.ts +4 -2
- package/dist/prepared-processor.js +75 -7
- package/dist/registry.js +10 -6
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- A company can put rules on the Vault purchases it chooses (a merchant list, a currency, a spend cap, a time window) by attaching a named preset to a stored card. A purchase the rules refuse now surfaces as `PresetRefusedError`, a typed decline: at stage `create` no authorization exists and nobody was asked; at stage `pre_replay` the authorization is `declined` with the rule's reason. It carries `code`, `presetName`, `rule`, `preset`, `attachment` (the card with its last four digits) and the rule's own statement; when several presets refuse the same purchase, `refusals` names every one and the other fields are the first. The adapters quiet the page's retry as for any decline, and a create-time refusal is never treated as a permanent misconfiguration.
|
|
6
|
+
- Requires the matching API and Vault release.
|
|
7
|
+
|
|
8
|
+
## 0.6.0
|
|
9
|
+
|
|
10
|
+
- Recognize Paysafe Checkout 1.8's exact hosted tokenization endpoints and preserve its native credential and correlation headers. The matching API registry and Vault deployment are required.
|
|
11
|
+
- Recognize Checkout.com card tokenization at `card-acquisition-gateway.checkout.com/tokens` and its sandbox counterpart alongside the existing API hosts. The matching backend registry and Vault deployment are required; this entry does not establish native merchant payment completion.
|
|
12
|
+
- Prepare Worldpay, Bambora and Mercado Pago checkout before the merchant's first Pay action. Use `psp: 'worldpay'` with `environment: 'production' | 'sandbox'`, or `psp: 'bambora' | 'mercado_pago'` with `environment: 'shared'`. Shared endpoints do not establish processor test mode. The merchant's credentials and checkout configuration determine that mode.
|
|
13
|
+
- Keep the existing selected-card, merchant, document, amount, currency and one-use consent checks. The native request begins only after approval, and approval readiness lasts at most 30 seconds. The SDK does not extend processor deadlines or automatically retry after payment uncertainty. Matching API, Vault and preparation migration are required.
|
|
14
|
+
- Bound Playwright and CDP setup with `attachmentTimeoutMs`, defaulting to 30 seconds. A stalled setup throws a sanitized `CheckoutAttachmentError`; late acknowledgements cannot start approval or retry setup, and concurrent setup failures report once. Close the failed checkout page and start a fresh context before trying again.
|
|
15
|
+
- Preserve the original setup failure across attached frames: a transport failure reports `unavailable`, a deadline reports `timeout`, and an observed page closure reports `closed`.
|
|
16
|
+
- Reject processor URLs with credentials or nondefault ports consistently across SDK and API discovery. Registry synchronization updates endpoint recognition; upgrading the SDK is required for the new preparation and setup behavior.
|
|
17
|
+
|
|
18
|
+
The matching Vault/API release adds Mollie card-token and supported Airwallex intent-confirmation replay through browser-owned TLS, preserves Worldpay's native session media type and Bambora's `cvd` field, and reports Nuvei's unambiguous validation error as processor refusal. Local regression and Chromium fixture results do not establish native processor acceptance or a completed merchant purchase.
|
|
19
|
+
|
|
3
20
|
## 0.5.0
|
|
4
21
|
|
|
5
22
|
- Prepare Braintree card checkout with `controller.prepare({ psp: 'braintree', environment: 'production' | 'sandbox' })` before the merchant's first Pay action. The cardholder approves and unlocks first; one fresh native request then uses that approval without another notification. The matching API and Vault release is required.
|
package/README.md
CHANGED
|
@@ -54,30 +54,28 @@ await attachToCdp(cdp, pageSessionId, {
|
|
|
54
54
|
vault,
|
|
55
55
|
user: 'usr_123', // whose card should pay
|
|
56
56
|
merchant: 'vanman.shop',
|
|
57
|
-
|
|
57
|
+
amount: 583, // your hint, an integer in the currency's smallest unit (or a decimal string: '5.83')
|
|
58
58
|
currency: 'usd', // "$5.83" is derived for the approval screen
|
|
59
59
|
onApprovalUrl: (url) => sendToUser(url), // iMessage, SMS, push, your call
|
|
60
60
|
});
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`amount:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
read show one amount. Tokenization requests carry no amount, so there the
|
|
80
|
-
pair is shown and reported (`amountAuthority: 'display_only'`), not enforced.
|
|
63
|
+
`amount` is your hint: an integer in the currency's smallest unit (583 for
|
|
64
|
+
$5.83), or a decimal string in normal units ('5.83'), with `currency`. The
|
|
65
|
+
processor's own amount is the higher authority: Agentcard reads it from the
|
|
66
|
+
paused request where the processor puts it there, or from the Stripe intent
|
|
67
|
+
the request names, right before the cardholder's device replays, and the
|
|
68
|
+
company's caps are judged on it. A hint lets a bad purchase be refused the
|
|
69
|
+
moment it opens; a hint more than one smallest unit away from the processor's
|
|
70
|
+
amount is refused with nothing charged (`AmountMismatchError`), and after the
|
|
71
|
+
replay the charge is reconciled against the approval
|
|
72
|
+
(`ReplayResponse.amountVerified`, `chargedAmount`, and `chargedKind`:
|
|
73
|
+
`captured` for a succeeded intent's `amount_received`, `authorized` for a
|
|
74
|
+
manual-capture intent's `amount_capturable`, `none` when nothing is collected
|
|
75
|
+
yet; plus the `checkout_authorization.amount_mismatch` webhook to your server
|
|
76
|
+
when the charge disagreed). Every result carries `amountAuthority`:
|
|
77
|
+
`processor`, `agent`, `page`, or `none`. A display string is never sent;
|
|
78
|
+
Agentcard derives it.
|
|
81
79
|
|
|
82
80
|
Then let your agent click "Pay" like it always does. `attachToCdp` pauses the
|
|
83
81
|
request for approval and resumes it only while the merchant request remains
|
|
@@ -129,8 +127,8 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
129
127
|
| Processor | Status |
|
|
130
128
|
|---|---|
|
|
131
129
|
| Shopify | supported, verified end to end |
|
|
132
|
-
| Stripe | tokenization replay and direct card-bearing PaymentIntent confirms are implemented; direct confirms
|
|
133
|
-
| Braintree card tokenization |
|
|
130
|
+
| Stripe | tokenization replay and direct card-bearing PaymentIntent confirms are implemented; direct confirms read the intent's amount back from Stripe; a hint sent as `amount` + `currency` must agree with it. Browser token-to-intent continuation is unsupported and held. Validate the exact merchant flow before pilot use |
|
|
131
|
+
| Braintree card tokenization | Prepared checkout supported; one live Haymarket Books ebook purchase with SDK `0.5.0` confirmed merchant fulfillment and SDK `completed` using a merchant receipt resolver. Independent processor capture/settlement, live 3DS and PayPal wallet flows remain unverified. |
|
|
134
132
|
| Checkout.com | supported |
|
|
135
133
|
| VGS Collect (Very Good Security; Wolt) | not supported: VGS's proxy aliases only submissions from its own iframe, so a replay from the cardholder's device is refused by the merchant (verified on Wolt, 2026-09-03). Not recognized, so the agent's browser is not paused there |
|
|
136
134
|
| Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it |
|
|
@@ -327,6 +325,16 @@ Playwright `CDPSession` is not the `CdpLike` interface. Raw CDP must preserve th
|
|
|
327
325
|
Initial arming errors reject `attachToCdp`; a child that cannot be armed remains
|
|
328
326
|
paused and reports `browser_interception_unavailable` for operator recovery.
|
|
329
327
|
|
|
328
|
+
Await attachment before clicking Pay. Both adapters stop waiting for browser
|
|
329
|
+
setup after 30 seconds and throw `CheckoutAttachmentError` with
|
|
330
|
+
`code: 'checkout_attachment_failed'` and `reason: 'timeout'`, `'closed'` or
|
|
331
|
+
`'unavailable'`. Use `attachmentTimeoutMs` to choose a setup deadline from 1 to
|
|
332
|
+
300000 milliseconds, separately from the approval's `timeoutMs`.
|
|
333
|
+
Close the failed checkout page and create a fresh browser context before
|
|
334
|
+
trying again. A late setup response cannot reopen the failed attachment or
|
|
335
|
+
request approval; intercepted card requests remain blocked. A setup failure
|
|
336
|
+
does not establish the status of any earlier purchase.
|
|
337
|
+
|
|
330
338
|
Use a checkout context created with `serviceWorkers: 'block'`. Playwright cannot
|
|
331
339
|
route requests intercepted by a service worker. The SDK rejects already active
|
|
332
340
|
service workers, but that check cannot prevent a site from registering one
|
|
@@ -342,7 +350,7 @@ value continues to work. Choose `requireMerchantResult: true` for a pilot:
|
|
|
342
350
|
|
|
343
351
|
```ts
|
|
344
352
|
const checkout = await attachToPlaywright(page, {
|
|
345
|
-
vault, user, merchant,
|
|
353
|
+
vault, user, merchant, amount, currency,
|
|
346
354
|
requireMerchantResult: true,
|
|
347
355
|
onStateChange: state => recordState(state),
|
|
348
356
|
onUserAction: action => deliverPrivatelyToUser(action),
|
|
@@ -385,7 +393,7 @@ Unrecognized merchant-server endpoints remain outside this guard unless listed
|
|
|
385
393
|
in `paymentEndpoints`; this is not a guarantee against a merchant charging a
|
|
386
394
|
saved token on its own server.
|
|
387
395
|
A direct card-bearing PaymentIntent confirm remains supported with the backend's
|
|
388
|
-
existing amount verification when `
|
|
396
|
+
existing amount verification when `amount` and `currency` are supplied.
|
|
389
397
|
|
|
390
398
|
Hosted-form submissions also always stay blocked because their payment outcome
|
|
391
399
|
is unverified. `reconcile()` calls the resolver once, coalescing concurrent calls.
|
|
@@ -400,24 +408,36 @@ do not reuse that token in a new attachment as a workaround. Configuration and
|
|
|
400
408
|
unsupported-mode failures require fixing the integration. Bank flows requiring
|
|
401
409
|
another confirmation and other stored-token chains remain unverified.
|
|
402
410
|
|
|
403
|
-
|
|
411
|
+
Worldpay, Bambora and Mercado Pago preparation requires SDK 0.6.0 or later and the matching API and Vault release.
|
|
412
|
+
|
|
413
|
+
Prepare a Square, Braintree, Worldpay, Bambora or Mercado Pago checkout before the first Pay action so the cardholder can approve before the native card request starts. The API and Vault deployments must support the selected processor:
|
|
404
414
|
|
|
405
415
|
```ts
|
|
406
416
|
const checkout = await attachToPlaywright(page, {
|
|
407
417
|
vault, user: 'your-user-id', merchant: 'Example merchant',
|
|
408
|
-
|
|
418
|
+
amount: 100, currency: 'USD',
|
|
409
419
|
onApprovalUrl: deliverPrivatelyToCardholder,
|
|
410
420
|
});
|
|
411
421
|
const preparation = await checkout.prepare({
|
|
412
|
-
psp: 'braintree',
|
|
413
|
-
environment: 'production', //
|
|
422
|
+
psp: 'braintree',
|
|
423
|
+
environment: 'production', // Square, Braintree and Worldpay: production or sandbox
|
|
414
424
|
});
|
|
415
425
|
// The cardholder has consented and unlocked the same approval document.
|
|
416
426
|
// No processor request or payment has started.
|
|
417
427
|
await page.getByRole('button', { name: 'Pay', exact: true }).click();
|
|
418
428
|
```
|
|
419
429
|
|
|
420
|
-
`prepare()` is available on both Playwright and raw CDP controllers. It requires `
|
|
430
|
+
`prepare()` is available on both Playwright and raw CDP controllers. It requires `amount` and `currency`, must precede the first recognized card request, and returns only when the cardholder's device is ready. It delivers the preparation URL through `onApprovalUrl` and `onUserAction`; binding the subsequent authorization sends no second approval link or SMS. The phone page must stay open. Its selected card, merchant origin, declared merchant, amount, currency, processor and environment bind one fresh request. The amount's authority is `agent`; a card token does not enforce the merchant's eventual charge amount.
|
|
431
|
+
|
|
432
|
+
| Processor | `environment` | Fresh native request |
|
|
433
|
+
| --- | --- | --- |
|
|
434
|
+
| Square | `production` or `sandbox` | Matching Square `/v2/card-nonce` host |
|
|
435
|
+
| Braintree | `production` or `sandbox` | Matching Braintree GraphQL host and guest `TokenizeCreditCard` mutation |
|
|
436
|
+
| Worldpay | `production` or `sandbox` | Matching Access Worldpay host and `/sessions/card` |
|
|
437
|
+
| Bambora | `shared` | `/scripts/tokenization/tokens` on `api.bam.shift4api.net` or `api.na.bambora.com` |
|
|
438
|
+
| Mercado Pago | `shared` | `api.mercadopago.com/v1/card_tokens` with a fresh card body |
|
|
439
|
+
|
|
440
|
+
Use `environment: 'shared'` for Bambora and Mercado Pago because the same endpoint serves test and live requests. Agentcard cannot establish the processor's test mode from that URL or a credential prefix. Configure test mode through the merchant's processor account when testing. Agentcard's own `sandbox` flag remains separate. Prepared Worldpay, Bambora and Mercado Pago requests reject saved-card and recurring request bodies; a refused request retires the local preparation. Reconcile any existing merchant attempt before creating a new attachment.
|
|
421
441
|
|
|
422
442
|
Braintree's native `ClientConfiguration` GraphQL query can run before, during or after preparation without using the approval. Only a single `TokenizeCreditCard` mutation can consume the prepared Braintree checkout. Prepared requests require guest card tokenization with explicit `options.validate: false`; omitted validation options, saved-card fields and `validate: true` are refused. Other GraphQL operations, batches and compound mutations are blocked. Braintree's legacy REST fallback cannot consume a prepared authorization.
|
|
423
443
|
|
|
@@ -472,9 +492,7 @@ The browser fixtures never contact a payment service. The general suite uses
|
|
|
472
492
|
allowlisted loopback proxy and a temporary self-signed TLS stub (requires the
|
|
473
493
|
`openssl` CLI). All other proxy destinations are rejected. These suites use an
|
|
474
494
|
in-process Agentcard API fixture and loopback merchant pages. The preparation
|
|
475
|
-
fixture denies all external traffic
|
|
476
|
-
card request, and then checks one fresh request with an unchanged ten-second
|
|
477
|
-
fixture abort timer. It exercises SDK ordering, not the native Square SDK. It proves nested-frame pause/resume, agent control during approval,
|
|
495
|
+
fixture denies all external traffic and waits beyond each modeled request deadline before any card request: eleven seconds for Square, sixty-one seconds for Braintree, and six and a half seconds for Worldpay, Bambora and Mercado Pago. Each fixture then checks one fresh request with an unchanged abort timer. The five-second timer matches the inspected Worldpay and Bambora source; the Mercado Pago timer is a test boundary, not a measured native deadline. The fixture exercises SDK ordering with native-shaped request bodies and synthetic responses, not processor acceptance. It proves nested-frame pause/resume, agent control during approval,
|
|
478
496
|
post-payment tasks in the same page, decline/expiry/cancel, unknown-outcome retry
|
|
479
497
|
blocking, explicit unsupported endpoint behavior, and blocking an immediate real-browser
|
|
480
498
|
Stripe token-to-intent fetch chain, including unrelated first intents, changed
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** An attachment failure has no payment or browser credentials in its message. */
|
|
2
|
+
export declare class CheckoutAttachmentError extends Error {
|
|
3
|
+
readonly reason: 'timeout' | 'closed' | 'unavailable';
|
|
4
|
+
readonly code = "checkout_attachment_failed";
|
|
5
|
+
constructor(reason: 'timeout' | 'closed' | 'unavailable');
|
|
6
|
+
}
|
|
7
|
+
/** Preserve a known setup cause without exposing raw transport errors. */
|
|
8
|
+
export declare function attachmentFailure(error: unknown): CheckoutAttachmentError;
|
|
9
|
+
export declare function attachmentDeadline(value: number | undefined): number;
|
|
10
|
+
/** Stop waiting, then reject every late continuation before its next command. */
|
|
11
|
+
export declare function withinAttachmentDeadline(arm: (assertActive: () => void) => Promise<void>, timeoutMs: number, signal: AbortSignal): Promise<void>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** An attachment failure has no payment or browser credentials in its message. */
|
|
2
|
+
export class CheckoutAttachmentError extends Error {
|
|
3
|
+
reason;
|
|
4
|
+
code = 'checkout_attachment_failed';
|
|
5
|
+
constructor(reason) {
|
|
6
|
+
super('Could not attach checkout interception. Close this checkout page and retry in a fresh browser context.');
|
|
7
|
+
this.reason = reason;
|
|
8
|
+
this.name = 'CheckoutAttachmentError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Preserve a known setup cause without exposing raw transport errors. */
|
|
12
|
+
export function attachmentFailure(error) {
|
|
13
|
+
return error instanceof CheckoutAttachmentError ? error : new CheckoutAttachmentError('unavailable');
|
|
14
|
+
}
|
|
15
|
+
export function attachmentDeadline(value) {
|
|
16
|
+
if (value === undefined)
|
|
17
|
+
return 30_000;
|
|
18
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > 300_000) {
|
|
19
|
+
throw new Error('attachmentTimeoutMs must be an integer between 1 and 300000.');
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
/** Stop waiting, then reject every late continuation before its next command. */
|
|
24
|
+
export async function withinAttachmentDeadline(arm, timeoutMs, signal) {
|
|
25
|
+
let stopped;
|
|
26
|
+
let timer;
|
|
27
|
+
let onAbort = () => { };
|
|
28
|
+
const assertActive = () => { if (stopped)
|
|
29
|
+
throw stopped; };
|
|
30
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
31
|
+
const stop = (failure) => { stopped ??= failure; reject(stopped); };
|
|
32
|
+
onAbort = () => stop(attachmentFailure(signal.reason));
|
|
33
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
34
|
+
if (signal.aborted)
|
|
35
|
+
onAbort();
|
|
36
|
+
else
|
|
37
|
+
timer = setTimeout(() => stop(new CheckoutAttachmentError('timeout')), timeoutMs);
|
|
38
|
+
});
|
|
39
|
+
try {
|
|
40
|
+
await Promise.race([deadline, Promise.resolve().then(() => { assertActive(); return arm(assertActive); })]);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
stopped ??= attachmentFailure(error);
|
|
44
|
+
throw stopped;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
signal.removeEventListener('abort', onAbort);
|
|
49
|
+
}
|
|
50
|
+
}
|
package/dist/braintree.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export type BraintreeEnvironment = 'production' | 'sandbox';
|
|
3
3
|
export type BraintreeRequestKind = 'configuration' | 'tokenization' | 'invalid';
|
|
4
4
|
export declare function braintreeEnvironment(url: string): BraintreeEnvironment | undefined;
|
|
5
|
+
/** Bounded duplicate-aware JSON for fresh-card preparation bodies. */
|
|
6
|
+
export declare function readTokenizationJson(body: string | null): Record<string, unknown> | null;
|
|
5
7
|
/** Undefined belongs to another processor; invalid Braintree requests stay blocked. */
|
|
6
8
|
export declare function classifyBraintreeRequest(url: string, method: string, body: string | null): BraintreeRequestKind | undefined;
|
|
7
9
|
/** Preparation accepts guest tokenization only; ordinary interception stays broader. */
|
package/dist/braintree.js
CHANGED
|
@@ -115,6 +115,18 @@ class JsonReader {
|
|
|
115
115
|
return value;
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
/** Bounded duplicate-aware JSON for fresh-card preparation bodies. */
|
|
119
|
+
export function readTokenizationJson(body) {
|
|
120
|
+
if (typeof body !== 'string' || body.length === 0 || body.length > MAX_BODY_LENGTH)
|
|
121
|
+
return null;
|
|
122
|
+
try {
|
|
123
|
+
const value = new JsonReader(body).read();
|
|
124
|
+
return record(value) ? value : null;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
118
130
|
/** Native operations need names, punctuation and variables, never literals. */
|
|
119
131
|
function lex(query) {
|
|
120
132
|
const tokens = [];
|
package/dist/cdp.d.ts
CHANGED
|
@@ -75,18 +75,32 @@ export interface AttachOptions extends LifecycleOptions {
|
|
|
75
75
|
vault: VaultClient;
|
|
76
76
|
user: string;
|
|
77
77
|
merchant: string;
|
|
78
|
-
/** Display string for the approval screen. Optional when amountCents + currency are given. */
|
|
79
|
-
amount?: string;
|
|
80
78
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* right before
|
|
79
|
+
* Your hint at the amount, an integer in the currency's smallest unit or a
|
|
80
|
+
* decimal string in normal units, with its ISO 4217 code. See
|
|
81
|
+
* AuthorizeInput.amount: the processor's own amount is the higher authority
|
|
82
|
+
* and is read right before the card is sent; a hint lets a bad purchase be
|
|
83
|
+
* refused the moment it opens, and one that disagrees with the processor is
|
|
84
|
+
* refused with nothing charged.
|
|
85
85
|
*/
|
|
86
|
-
|
|
86
|
+
amount?: number | string;
|
|
87
87
|
currency?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The total the checkout page shows, the lowest authority: used only when
|
|
90
|
+
* neither the processor's request nor your `amount` names one. Pass a reader
|
|
91
|
+
* that returns an integer in the currency's smallest unit with its code
|
|
92
|
+
* (`{ amount: 4210, currency: 'usd' }`), read off the page however your
|
|
93
|
+
* page spells it; the adapters call it when a card request pauses, give it
|
|
94
|
+
* one second, and send nothing when it yields nothing. Absent: no page total.
|
|
95
|
+
*/
|
|
96
|
+
pageAmount?: () => Promise<{
|
|
97
|
+
amount: number;
|
|
98
|
+
currency: string;
|
|
99
|
+
} | undefined>;
|
|
88
100
|
cardId?: string;
|
|
89
101
|
timeoutMs?: number;
|
|
102
|
+
/** Browser interception setup deadline, separate from approval. Defaults to 30000 ms; maximum 300000 ms. */
|
|
103
|
+
attachmentTimeoutMs?: number;
|
|
90
104
|
/** Explicit payment endpoints to block if the registry cannot handle their method/format. Unlisted traffic is untouched. */
|
|
91
105
|
paymentEndpoints?: readonly PaymentEndpointGuard[];
|
|
92
106
|
onApprovalUrl?: (url: string) => void;
|