@agent-cards/checkout 0.12.0 → 0.14.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 +14 -0
- package/PREFLIGHT.md +13 -5
- package/README.md +17 -4
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/client.js +20 -1
- package/dist/lifecycle.js +6 -1
- package/dist/preflight-capabilities.generated.d.ts +63 -0
- package/dist/preflight-capabilities.generated.js +97 -0
- package/dist/preflight-catalog.json +678 -8
- package/dist/preflight-playwright.js +143 -50
- package/dist/preflight-schemas.json +54 -7
- package/dist/preflight.generated.d.ts +74 -1
- package/dist/preflight.generated.js +82 -8
- package/dist/prepared-processor.d.ts +1 -1
- package/dist/prepared-processor.js +6 -1
- package/dist/spreedly.generated.d.ts +10 -0
- package/dist/spreedly.generated.js +332 -0
- package/dist/stripe-checkout.generated.js +9 -1
- package/examples/preflight/kernel-native/inventory.json +11 -2
- package/examples/preflight/kernel-profile.empty.json +1 -1
- package/examples/preflight/mollie-hosted.result.json +2 -2
- package/examples/preflight/stripe-script.direct.result.json +2 -2
- package/examples/preflight/stripe-script.result.json +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Approve Spreedly's native hosted-card checkout with `prepare({ psp: 'spreedly', environment: 'shared' })`. The Vault tokenizes the selected card over the encrypted relay and returns the native response. Matching API, Vault, relay and database releases are required; tokenization alone does not confirm payment. Saved-card updates and other Spreedly flows remain unsupported.
|
|
6
|
+
|
|
7
|
+
- Identify hosted, regional, and versioned processor variants seen on live checkouts: Adyen secured fields on the regional live hosts and any release, the Square card element frame, dLocal Smart Fields releases, Mercado Pago secure fields and the guest Checkout Pro card form, and the Rapyd hosted checkout page. The Tranzila terminal-root page, the Authorize.Net hosted payment form, and Worldpay hosted payment pages identify their processor and return `unknown` with `processor_variant_unverified`. The catalog is `2026-09-15.1`; issue native profiles against it.
|
|
8
|
+
|
|
9
|
+
- Report a sole script-only candidate as `psp` only when the observation is complete. On a partial scan the script stays in `candidates` as `undetermined`, so a co-loaded SDK is never presented as the selected processor.
|
|
10
|
+
|
|
11
|
+
- Detect visible card controls in nested frames from field metadata only, never values. When those controls sit on a site no evidenced processor owns, the collector reports `card_entry_unrecognized`, the observation is incomplete, and the result stays `unknown`. Callers supplying their own observations can report the same reason.
|
|
12
|
+
|
|
13
|
+
- Match discovery rules on the origin and path only. A long query string on an unrelated wallet or widget frame no longer invalidates the observation. `invalid_url` covers unparsable locations, an origin and path over `4096` characters, or a raw location over `65536` characters.
|
|
14
|
+
|
|
15
|
+
- Compare committed frame URLs with committed frame URLs. A script-created frame that inherits the merchant URL through `document.open()` no longer reports `navigation_changed`; real navigations, added frames, and removed frames still do.
|
|
16
|
+
|
|
17
|
+
- Read frames one nesting level at a time with up to eight frames in flight, and release frame handles while the document read proceeds. Frame-heavy checkouts over a remote CDP connection fit the default 1,500 ms budget far more often. `collection.timeoutMs` remains available for slower connections.
|
|
18
|
+
|
|
5
19
|
- Complete a merchant-confirmed payment when the merchant supplies no order or receipt ID. Return `{ status: 'completed', confirmation: { kind: 'merchant_payment', authorizationId } }` from the merchant resolver using the current checkout authorization. The resolver must verify the original payment request, amount, currency, selected card and merchant success; HTTP 200 or a success page alone is insufficient. The completed state carries `confirmation` without inventing `orderId`, clears stale reasons and continues to block another payment. Existing completion results with a genuine `orderId` keep working.
|
|
6
20
|
|
|
7
21
|
- Approve a Recurly checkout before its native card request starts. Call `prepare` with `psp: 'recurly'` and `environment: 'shared'`, then submit the merchant's form once. The same selected card and approved purchase bind a new-card POST on the US or EU endpoint. The matching API, database migration and Vault release are required. Token issuance and merchant payment completion remain separate results.
|
package/PREFLIGHT.md
CHANGED
|
@@ -93,7 +93,7 @@ The [Mollie fixture](./examples/preflight/mollie-hosted.observations.json) ident
|
|
|
93
93
|
| `signals[].visible` | `true`, `false`, or `null` when visibility is undetermined. Do not mark scripts active merely because they loaded. |
|
|
94
94
|
| `observation.complete` | Whether the scan finished without missing observations. |
|
|
95
95
|
| `observation.truncated` | Whether a collection limit discarded observations. |
|
|
96
|
-
| `observation.reasons` | Documented collection reason codes for an incomplete observation. |
|
|
96
|
+
| `observation.reasons` | Documented collection reason codes for an incomplete observation. Report `card_entry_unrecognized` when your own collector sees visible card controls in a nested frame on a site no evidenced processor owns. |
|
|
97
97
|
|
|
98
98
|
The normalized snapshot contains `schema_version: 1`, `catalog_version`, rule identifiers, frame relationships, and collection status. Raw URLs do not survive normalization. The assessment returns PSP candidates with reviewed evidence, support status and its scope, any identified flow, reason codes, and limitations. `scenario_defaulted` records whether the caller omitted the scenario and accepted `one_time`.
|
|
99
99
|
|
|
@@ -171,12 +171,15 @@ The catalog includes reviewed discovery rules and direct SDK implementation capa
|
|
|
171
171
|
| Mollie | `token` |
|
|
172
172
|
| Paysafe | `token` |
|
|
173
173
|
| Recurly | `token` |
|
|
174
|
+
| Spreedly | `token` |
|
|
174
175
|
| Moneris | `token` |
|
|
175
176
|
| Bambora | `token` |
|
|
176
177
|
| Global Payments | `token` |
|
|
177
178
|
|
|
178
179
|
The bundled direct SDK profile declares processor support for `one_time` purchases. The catalog carries each processor's request limitations and known exclusions. A detection rule does not cover every product or regional variant sold under the processor's name. For example, Moneris Hosted Tokenization and Moneris Checkout use different payment paths; the implemented adapter covers Hosted Tokenization.
|
|
179
180
|
|
|
181
|
+
The catalog also carries reviewed hosted, regional, and versioned variants observed on live checkouts: Adyen secured fields on the regional live hosts and any release, the Square card element frame, dLocal Smart Fields releases, Mercado Pago secure fields and the guest Checkout Pro card form, and the Rapyd hosted checkout page. A variant the implemented adapter does not admit, such as the Tranzila terminal-root page, the Authorize.Net hosted payment form, or a Worldpay hosted payment page, identifies its processor and returns `unknown` with `processor_variant_unverified`. A new fingerprint never declares payment support by itself.
|
|
182
|
+
|
|
180
183
|
| Observed checkout | Classification |
|
|
181
184
|
| --- | --- |
|
|
182
185
|
| A compatible Stripe script, `one_time`, direct SDK | `supported` at `processor_integration` scope; `checkout_flow_status` remains `unknown`. |
|
|
@@ -184,6 +187,8 @@ The bundled direct SDK profile declares processor support for `one_time` purchas
|
|
|
184
187
|
| A detected processor with an empty Kernel native profile | `unknown`; the native adapter has not declared processor or flow support. |
|
|
185
188
|
| Competing processors without enough evidence to select one | `unknown`, with `checkout_flow_status: "ambiguous"`. |
|
|
186
189
|
| An incomplete observation | `unknown`; inspect again after the checkout settles. |
|
|
190
|
+
| A single processor script during an incomplete scan | `unknown`; `psp` stays `null` and the script remains in `candidates` as `undetermined` until a complete scan confirms it. |
|
|
191
|
+
| Visible card controls in a nested frame on a site no evidenced processor owns | `unknown` with `card_entry_unrecognized`; a co-loaded SDK script is listed as a candidate, not as the processor. |
|
|
187
192
|
|
|
188
193
|
Processor support does not establish which payment method the merchant selected. Many SDKs also load wallets or fraud checks before a card form appears. Read `checkout_flow_status` and the returned limitations alongside `status`; never present `supported` alone as a promise that a merchant purchase will succeed.
|
|
189
194
|
|
|
@@ -208,7 +213,7 @@ Declare processor support and flow support separately. A flow entry cannot estab
|
|
|
208
213
|
|
|
209
214
|
Take PSP identifiers, payment modes, flow identifiers, operation identifiers, and operation revisions from the packaged catalog. Verify each combination against the named adapter version before adding a `supported` entry. Use `unsupported` only for a known exclusion. A profile with a wrong schema, incompatible catalog, mismatched adapter version, or expired timestamp preserves `unknown`.
|
|
210
215
|
|
|
211
|
-
The JSON contract uses `schema_version: 1`. The catalog bundled with this release uses `catalog_version: "2026-09-
|
|
216
|
+
The JSON contract uses `schema_version: 1`. The catalog bundled with this release uses `catalog_version: "2026-09-15.1"`. Keep the snapshot, classifier, and profile on the same catalog version. Re-normalize observations with the installed package after changing the catalog. Review the adapter declarations before issuing a compatible profile; changing the version string alone does not validate new behavior.
|
|
212
217
|
|
|
213
218
|
Kernel can integrate the JSON contract immediately and supply its validated native capabilities later. No deployed Agentcard endpoint or payment request is required for that work.
|
|
214
219
|
|
|
@@ -235,7 +240,7 @@ The current inventory leaves every native runtime status `unknown`. Kernel docum
|
|
|
235
240
|
| `checkout_flow_status: "unknown"` | The observations do not identify the exact checkout flow. Processor support can still be known. |
|
|
236
241
|
| `checkout_flow_status: "ambiguous"` | Competing evidence prevents a single flow assessment. Inspect after the payment method is selected. |
|
|
237
242
|
|
|
238
|
-
A loaded PSP script establishes a possible processor, not necessarily the active card flow. The helper returns candidates rather than picking the first script. A missing fingerprint does not establish lack of support.
|
|
243
|
+
A loaded PSP script establishes a possible processor, not necessarily the active card flow. The helper returns candidates rather than picking the first script. A sole script candidate becomes `psp` only when the observation is complete. When a visible card-entry frame belongs to no evidenced processor's site, the collector reports `card_entry_unrecognized` and the script stays a candidate. A missing fingerprint does not establish lack of support.
|
|
239
244
|
|
|
240
245
|
Every assessment is an advisory hint. The existing payment request checks still apply. A supported flow can require authentication or merchant configuration, and only the merchant's payment result establishes whether a purchase succeeded.
|
|
241
246
|
|
|
@@ -278,9 +283,10 @@ Collection reasons explain why an observation is partial:
|
|
|
278
283
|
| `signal_limit` | Preserve `unknown` when the page exceeds the observation limit. |
|
|
279
284
|
| `snapshot_limit` | Preserve `unknown` when the observations exceed the size budget. |
|
|
280
285
|
| `frame_unavailable` | Inspect again after the frame is available. |
|
|
281
|
-
| `navigation_changed` | Inspect the new checkout state after navigation finishes. |
|
|
286
|
+
| `navigation_changed` | A frame's committed URL changed, a frame was added or removed, or an http(s) document's URL changed during the scan. A script-created frame that inherits the merchant URL is not a navigation. Inspect the new checkout state after navigation finishes. |
|
|
287
|
+
| `card_entry_unrecognized` | Visible card controls sit in a nested frame on a site that no evidenced processor owns, or no processor evidence was found at all. Treat listed candidates as unconfirmed and inspect again after the payment method is selected. Identification needs a reviewed fingerprint for that frame. |
|
|
282
288
|
| `invalid_observation` | Validate raw observations against the packaged schema. |
|
|
283
|
-
| `invalid_url` |
|
|
289
|
+
| `invalid_url` | The location could not be parsed, its origin and path exceed `4096` characters, or the raw location exceeds `65536` characters. Matching reads the origin and path only, so a long query string on an unrelated frame never invalidates an observation. |
|
|
284
290
|
| `collection_incomplete` | Inspect again after the underlying collection problem is resolved. |
|
|
285
291
|
|
|
286
292
|
## Keep observations current
|
|
@@ -293,6 +299,8 @@ Collect only the documented asset observations when using your own browser tools
|
|
|
293
299
|
|
|
294
300
|
The default collection budget is `1500` milliseconds, with at most `64` frames, `2048` signals, and `262144` serialized snapshot bytes. Set lower bounds through `collection.timeoutMs`, `collection.maxFrames`, `collection.maxSignals`, or `collection.maxSnapshotBytes` on `inspectCheckout`. The maximum time budget is `10000` milliseconds; the remaining limits cannot exceed their defaults. The minimum snapshot budget is `512` bytes.
|
|
295
301
|
|
|
302
|
+
Frames are read one nesting level at a time with up to eight frames in flight, and each frame handle is released while its document read proceeds. A remote CDP connection therefore pays about three round trips per nesting level plus one per eight frames, rather than four round trips per frame. Over a remote connection, allow `3000` to `5000` milliseconds through `collection.timeoutMs`, inspect after the payment controls have loaded, and read `observation.reasons` before retrying. A longer budget cannot repair a scan that started before the checkout settled.
|
|
303
|
+
|
|
296
304
|
## Validate without a purchase
|
|
297
305
|
|
|
298
306
|
The included fixture is synthetic and contains no card information. Fixture classifications validate the detector contract; they are not evidence of a real payment or of a merchant's coverage.
|
package/README.md
CHANGED
|
@@ -84,8 +84,8 @@ Agentcard derives it.
|
|
|
84
84
|
Then let your agent click "Pay" like it always does. `attachToCdp` pauses the
|
|
85
85
|
request for approval and resumes it only while the merchant request remains
|
|
86
86
|
live. Merchant timeouts still apply: Square's observed tokenization deadline
|
|
87
|
-
is about 10 seconds,
|
|
88
|
-
`controller.prepare()` before the first Pay action as shown below.
|
|
87
|
+
is about 10 seconds, Braintree's native request timeout is 60 seconds, and Adyen Web's own request timeout abandons its Sessions payment call 60 seconds after Pay (observed on Adyen Web 6.41 and 6.44), each including approval and handoff. These are the processors' limits, not ones the SDK enforces: the SDK's own authorization wait stays 15 minutes. For human approval, use
|
|
88
|
+
`controller.prepare()` before the first Pay action as shown below. Adyen is not on the `prepare()` list yet, so an Adyen approval has to land within Adyen Web's minute.
|
|
89
89
|
|
|
90
90
|
Playwright:
|
|
91
91
|
|
|
@@ -136,7 +136,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
136
136
|
| Checkout.com | supported |
|
|
137
137
|
| Mercado Pago | Card tokenization and prepared checkout are implemented. Guest Checkout Pro in Mexico also corrects the issuer for one native card association when the selected card has the same brand and type. One live MXN 40 Lotería Chida purchase with published SDK 0.10.0 completed automatically through Pay; the merchant confirmed paid status and PDF fulfillment. The historical SDK result remains unknown because the private receipt adapter rejected a relative download URL; a separate read with the corrected adapter confirms that same paid receipt. Independent processor capture/settlement and other country or integration paths remain unverified. |
|
|
138
138
|
| 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 |
|
|
139
|
-
| Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it |
|
|
139
|
+
| Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it. Sessions flow only: the paused request is `/checkoutshopper/v1/sessions/{id}/payments` on Adyen's own hosts; a merchant that posts the encrypted fields to its own server is not recognized, so nothing pauses there. Approval starts at Pay and must land before Adyen Web's own request timeout (observed at 60 seconds on Adyen Web 6.41 and 6.44; not enforced by the SDK); `prepare()` is not available for Adyen yet |
|
|
140
140
|
| Tranzila | supported (mode `hosted_form`): the cardholder finishes on Tranzila's own page; the paused form navigation resolves to a synthetic page, and you poll the merchant's order state |
|
|
141
141
|
|
|
142
142
|
The recognizer list is fetched from the API at runtime (`vault.syncRegistry()`),
|
|
@@ -514,8 +514,19 @@ await page.getByRole('button', { name: 'Pay', exact: true }).click();
|
|
|
514
514
|
| Bambora | `shared` | `/scripts/tokenization/tokens` on `api.bam.shift4api.net` or `api.na.bambora.com` |
|
|
515
515
|
| Mercado Pago | `shared` | `api.mercadopago.com/v1/card_tokens` with a fresh card body |
|
|
516
516
|
| Recurly | `shared` | Form-encoded POST to `/js/v1/token` on `api.recurly.com` or `api.eu.recurly.com` |
|
|
517
|
+
| Spreedly | `shared` | Native iframe JSON POST to `/v1/payment_methods/restricted.json` on `core.spreedly.com` |
|
|
517
518
|
|
|
518
|
-
Use `environment: 'shared'` for Bambora, Mercado Pago and
|
|
519
|
+
Use `environment: 'shared'` for Bambora, Mercado Pago, Recurly and Spreedly 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, Mercado Pago and Recurly 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.
|
|
520
|
+
|
|
521
|
+
Prepare a Spreedly checkout before submitting the merchant's card form:
|
|
522
|
+
|
|
523
|
+
```ts
|
|
524
|
+
await controller.prepare({ psp: 'spreedly', environment: 'shared' });
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
After approval, submit the form once. The Vault replaces the card fields on your device and sends the native request through an encrypted connection to Spreedly. The merchant's environment and signed session stay unchanged. The API, Vault, relay and preparation migration must support Spreedly before you use this flow; the API refuses preparations while its relay rollout flag is disabled.
|
|
528
|
+
|
|
529
|
+
Initial coverage includes the hosted iframe's new-card request. Saved-card CVV updates, Express, wallets, bank accounts and gateway purchase APIs require separate support. A returned card token does not confirm payment; wait for the merchant's result before reporting success. Autopilot is unavailable for Spreedly.
|
|
519
530
|
|
|
520
531
|
Prepare Recurly before clicking the merchant's payment button:
|
|
521
532
|
|
|
@@ -629,6 +640,8 @@ For controlled hosted Stripe Checkout, both attachment functions accept `stripeC
|
|
|
629
640
|
|
|
630
641
|
The SDK answers dummy-card tokenization locally, then sends the browser's final native confirmation through the shared core and enclave. The local response is preparation only: it creates no authorization and makes no processor request. The final result includes `checkoutSessionId` only after the selected grant, restricted terminal response, and captured amount have been checked. Continue to confirm the merchant order through the checkout controller.
|
|
631
642
|
|
|
643
|
+
When Agentcard reports `autopilot_status: action_required` for the same authorization and grant, the SDK stops waiting and calls `onUserAction` with `reason: 'other'` and the authorization ID. The checkout controller records `requires_user_action` and holds further card requests. A direct `VaultClient.authorize()` call rejects with `PaymentOutcomeUnknownError` and reason `autopilot_action_required`. The existing authorization and reservation remain held; the SDK does not cancel or create another payment, return a processor payload, or infer a 3DS challenge. Your application's `resolveMerchantResult` can report the authoritative outcome of this same payment through `reconcile()`. Challenge execution and automatic continuation are not provided by this status report.
|
|
644
|
+
|
|
632
645
|
The shared core carries a validated billing email from that tokenization request into the final confirmation before authorization. The email stays bound to the same Session and local PaymentMethod reference. Missing email stays missing; duplicate or conflicting values are refused. The SDK does not fill an email from the Agentcard account or invent one for the merchant.
|
|
633
646
|
|
|
634
647
|
This integration requires matching backend and measured executor releases. TEST and LIVE have separate admission controls. LIVE also requires a newly authorized production grant on the selected real card, a fixed merchant account/profile with exactly one complete fixed-price USD line item and an independently reviewed operation qualification reference; the SDK option supplies none of these. LIVE deployment remains unqualified and disabled until that evidence exists. Exact observed totals do not establish atomic amount enforcement by Stripe. Subscriptions, saved-card flows and authentication continuations remain excluded. An unavailable preparation or uncertain result is declined or held for reconciliation; it cannot switch to a competing human-approval payment.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const BUILTIN_REGISTRY = [{ "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i] }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "moneris", "match": /(www3|esqa|gateway|gatewayqa|gatewayt|gatewaydev)\.moneris\.com\/HPPtoken\/request\.php/i, "hosts": ["^www3\\.moneris\\.com$", "^esqa\\.moneris\\.com$", "^gateway\\.moneris\\.com$", "^gatewayqa\\.moneris\\.com$", "^gatewayt\\.moneris\\.com$", "^gatewaydev\\.moneris\\.com$"], "encoding": "form", "passthroughHeaders": [] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }];
|
|
1
|
+
export const BUILTIN_REGISTRY = [{ "psp": "spreedly", "match": /core\.spreedly\.com\/v1\/payment_methods\/restricted\.json/i, "hosts": ["^core\\.spreedly\\.com$"], "encoding": "json", "passthroughHeaders": [/^spreedly-environment-key$/i] }, { "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i] }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "moneris", "match": /(www3|esqa|gateway|gatewayqa|gatewayt|gatewaydev)\.moneris\.com\/HPPtoken\/request\.php/i, "hosts": ["^www3\\.moneris\\.com$", "^esqa\\.moneris\\.com$", "^gateway\\.moneris\\.com$", "^gatewayqa\\.moneris\\.com$", "^gatewayt\\.moneris\\.com$", "^gatewaydev\\.moneris\\.com$"], "encoding": "form", "passthroughHeaders": [] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }];
|
package/dist/client.js
CHANGED
|
@@ -696,6 +696,21 @@ export class VaultClient {
|
|
|
696
696
|
catch { /* observer only */ }
|
|
697
697
|
};
|
|
698
698
|
let failed = false;
|
|
699
|
+
let actionRequired = false;
|
|
700
|
+
const checkAutopilotAction = (state) => {
|
|
701
|
+
if (state.autopilot_status !== 'action_required')
|
|
702
|
+
return;
|
|
703
|
+
// The authenticated API reports only a verified completion category.
|
|
704
|
+
// Retain this authorization without returning its processor payload or
|
|
705
|
+
// inferring whether the required action is 3DS, a redirect, or another step.
|
|
706
|
+
if (state.id !== authorizationId || state.status !== 'awaiting_approval' || state.mode !== 'token'
|
|
707
|
+
|| state.execution_mode !== 'autopilot' || execution.executionMode !== 'autopilot'
|
|
708
|
+
|| state.grant_id !== execution.grantId || (input.grantId && state.grant_id !== input.grantId)) {
|
|
709
|
+
throw new PaymentOutcomeUnknownError(authorizationId, 'autopilot_action_unconfirmed');
|
|
710
|
+
}
|
|
711
|
+
actionRequired = true;
|
|
712
|
+
throw new PaymentOutcomeUnknownError(authorizationId, 'autopilot_action_required');
|
|
713
|
+
};
|
|
699
714
|
const stopSignal = input.merchantSignal
|
|
700
715
|
? AbortSignal.any([input.merchantSignal, ...(input.signal ? [input.signal] : [])]) : input.signal;
|
|
701
716
|
try {
|
|
@@ -706,6 +721,7 @@ export class VaultClient {
|
|
|
706
721
|
if (input.merchantSignal?.aborted)
|
|
707
722
|
throw new PaymentOutcomeUnknownError(authorizationId, 'merchant_request_aborted');
|
|
708
723
|
execution = executionMetadata(created, authorizationId);
|
|
724
|
+
checkAutopilotAction(created);
|
|
709
725
|
deliverApproval(created);
|
|
710
726
|
while (Date.now() < deadline) {
|
|
711
727
|
if (stopSignal?.aborted)
|
|
@@ -729,6 +745,7 @@ export class VaultClient {
|
|
|
729
745
|
throw new PaymentOutcomeUnknownError(authorizationId, 'authorization_status_malformed');
|
|
730
746
|
}
|
|
731
747
|
execution = executionMetadata(s, authorizationId, execution);
|
|
748
|
+
checkAutopilotAction(s);
|
|
732
749
|
if (nativeCheckout && (s.status === 'submitted_on_device' ||
|
|
733
750
|
(s.status === 'approved' && (s.mode !== 'token' || execution.executionMode !== 'autopilot'
|
|
734
751
|
|| execution.grantId !== input.grantId))))
|
|
@@ -885,7 +902,9 @@ export class VaultClient {
|
|
|
885
902
|
throw error;
|
|
886
903
|
}
|
|
887
904
|
finally {
|
|
888
|
-
|
|
905
|
+
// An attested action-required result retains its claim and reservation.
|
|
906
|
+
// Reporting that state must not request cancellation of the same attempt.
|
|
907
|
+
if (!actionRequired && (input.merchantSignal?.aborted || ((preparation || nativeCheckout) && failed))) {
|
|
889
908
|
// Drain a create acknowledgement even after the merchant aborts so its
|
|
890
909
|
// known ID can be retired. An unacknowledged create remains unknown.
|
|
891
910
|
// A started/finalized replay or failed cleanup never becomes a claimed
|
package/dist/lifecycle.js
CHANGED
|
@@ -139,7 +139,12 @@ export class CheckoutLifecycle {
|
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
const authorizationId = error instanceof PaymentOutcomeUnknownError || error instanceof ProcessorRefusedError ? error.authorizationId : this.state.authorizationId;
|
|
142
|
-
if (handoffStarted
|
|
142
|
+
if (!handoffStarted && error instanceof PaymentOutcomeUnknownError && error.reason === 'autopilot_action_required') {
|
|
143
|
+
this.held = true;
|
|
144
|
+
this.set({ ...this.state, authorizationId, status: 'requires_user_action', reason: 'other' });
|
|
145
|
+
this.notify({ reason: 'other', authorizationId });
|
|
146
|
+
}
|
|
147
|
+
else if (handoffStarted || error instanceof PaymentOutcomeUnknownError || error instanceof IntentNotConfirmableError) {
|
|
143
148
|
this.held = true;
|
|
144
149
|
this.set({ ...this.state, authorizationId, status: 'outcome_unknown', reason: error instanceof PaymentOutcomeUnknownError ? error.reason : error instanceof IntentNotConfirmableError ? 'intent_not_confirmable' : 'browser_handoff_failed' });
|
|
145
150
|
}
|
|
@@ -3,6 +3,69 @@ export declare const CHECKOUT_PREFLIGHT_CAPABILITIES: {
|
|
|
3
3
|
readonly scope: "processor_integration";
|
|
4
4
|
readonly integration: "direct_sdk";
|
|
5
5
|
readonly processors: readonly [{
|
|
6
|
+
readonly psp: "spreedly";
|
|
7
|
+
readonly status: "supported";
|
|
8
|
+
readonly mode: "token";
|
|
9
|
+
readonly operations: readonly [{
|
|
10
|
+
readonly id: "spreedly.card_request";
|
|
11
|
+
readonly effect: "processor_specific_card_request";
|
|
12
|
+
readonly amount_binding: "unestablished";
|
|
13
|
+
readonly psp: "spreedly";
|
|
14
|
+
readonly version: 1;
|
|
15
|
+
readonly mode: "token";
|
|
16
|
+
readonly autopilot_eligible: false;
|
|
17
|
+
readonly requires: "reviewed_final_payment_and_continuation_evidence";
|
|
18
|
+
}];
|
|
19
|
+
readonly scenarios: {
|
|
20
|
+
readonly one_time: {
|
|
21
|
+
readonly status: "supported";
|
|
22
|
+
readonly reason: "card_request_adapter_implemented";
|
|
23
|
+
readonly requirements: readonly ["actual_payment_request_validation", "merchant_confirmation"];
|
|
24
|
+
};
|
|
25
|
+
readonly save_card: {
|
|
26
|
+
readonly status: "conditional";
|
|
27
|
+
readonly reason: "merchant_card_storage_and_consent_required";
|
|
28
|
+
readonly requirements: readonly ["actual_payment_request_validation", "merchant_confirmation", "stored_card_consent", "merchant_card_saved"];
|
|
29
|
+
};
|
|
30
|
+
readonly subscription_initial: {
|
|
31
|
+
readonly status: "conditional";
|
|
32
|
+
readonly reason: "merchant_card_storage_and_consent_required";
|
|
33
|
+
readonly requirements: readonly ["actual_payment_request_validation", "merchant_confirmation", "stored_card_consent", "merchant_subscription_confirmation"];
|
|
34
|
+
};
|
|
35
|
+
readonly subscription_renewal: {
|
|
36
|
+
readonly status: "outside_vault";
|
|
37
|
+
readonly reason: "renewal_managed_by_merchant";
|
|
38
|
+
readonly requirements: readonly ["verify_merchant_billing"];
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
readonly limitations: readonly ["Only the listed request format is recognized; a recognized processor is not verified merchant coverage.", "The adapter handles the Spreedly iframe v1 restricted endpoint for new credit cards through the encrypted relay.", "The merchant environment and optional signed iframe session must remain valid. Expired signatures require a fresh merchant checkout.", "Spreedly creates a payment-method token; the merchant still completes any gateway payment and authentication."];
|
|
42
|
+
readonly unsupported_variants: readonly [{
|
|
43
|
+
readonly variant: "general_javascript_api";
|
|
44
|
+
readonly status: "unsupported";
|
|
45
|
+
readonly constraint: "direct_sdk";
|
|
46
|
+
readonly reason: "The general payment_methods.json endpoint is outside the reviewed native iframe path.";
|
|
47
|
+
}, {
|
|
48
|
+
readonly variant: "saved_card_or_recache";
|
|
49
|
+
readonly status: "unsupported";
|
|
50
|
+
readonly constraint: "direct_sdk";
|
|
51
|
+
readonly reason: "Stored tokens and CVV-only recache requests are outside new-card tokenization.";
|
|
52
|
+
}, {
|
|
53
|
+
readonly variant: "click_to_pay_or_bank_account";
|
|
54
|
+
readonly status: "unsupported";
|
|
55
|
+
readonly constraint: "direct_sdk";
|
|
56
|
+
readonly reason: "Click to Pay and bank-account request shapes require separate validation.";
|
|
57
|
+
}, {
|
|
58
|
+
readonly variant: "gateway_purchase_or_distribution";
|
|
59
|
+
readonly status: "unsupported";
|
|
60
|
+
readonly constraint: "direct_sdk";
|
|
61
|
+
readonly reason: "Gateway transactions and payment-method distribution are outside the card tokenization adapter.";
|
|
62
|
+
}];
|
|
63
|
+
readonly processor_amount: "none";
|
|
64
|
+
readonly challenge_surface: "merchant_browser";
|
|
65
|
+
readonly merchant_confirmation_required: true;
|
|
66
|
+
readonly live_validation: "not_established_by_catalog";
|
|
67
|
+
readonly sources: readonly ["src/definitions.js", "src/operations.js", "src/backend.js", "src/spreedly.js", "../checkout/src/prepared-processor.ts"];
|
|
68
|
+
}, {
|
|
6
69
|
readonly psp: "shopify";
|
|
7
70
|
readonly status: "supported";
|
|
8
71
|
readonly mode: "token";
|
|
@@ -5,6 +5,103 @@ export const CHECKOUT_PREFLIGHT_CAPABILITIES = {
|
|
|
5
5
|
"scope": "processor_integration",
|
|
6
6
|
"integration": "direct_sdk",
|
|
7
7
|
"processors": [
|
|
8
|
+
{
|
|
9
|
+
"psp": "spreedly",
|
|
10
|
+
"status": "supported",
|
|
11
|
+
"mode": "token",
|
|
12
|
+
"operations": [
|
|
13
|
+
{
|
|
14
|
+
"id": "spreedly.card_request",
|
|
15
|
+
"effect": "processor_specific_card_request",
|
|
16
|
+
"amount_binding": "unestablished",
|
|
17
|
+
"psp": "spreedly",
|
|
18
|
+
"version": 1,
|
|
19
|
+
"mode": "token",
|
|
20
|
+
"autopilot_eligible": false,
|
|
21
|
+
"requires": "reviewed_final_payment_and_continuation_evidence"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"scenarios": {
|
|
25
|
+
"one_time": {
|
|
26
|
+
"status": "supported",
|
|
27
|
+
"reason": "card_request_adapter_implemented",
|
|
28
|
+
"requirements": [
|
|
29
|
+
"actual_payment_request_validation",
|
|
30
|
+
"merchant_confirmation"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"save_card": {
|
|
34
|
+
"status": "conditional",
|
|
35
|
+
"reason": "merchant_card_storage_and_consent_required",
|
|
36
|
+
"requirements": [
|
|
37
|
+
"actual_payment_request_validation",
|
|
38
|
+
"merchant_confirmation",
|
|
39
|
+
"stored_card_consent",
|
|
40
|
+
"merchant_card_saved"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"subscription_initial": {
|
|
44
|
+
"status": "conditional",
|
|
45
|
+
"reason": "merchant_card_storage_and_consent_required",
|
|
46
|
+
"requirements": [
|
|
47
|
+
"actual_payment_request_validation",
|
|
48
|
+
"merchant_confirmation",
|
|
49
|
+
"stored_card_consent",
|
|
50
|
+
"merchant_subscription_confirmation"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"subscription_renewal": {
|
|
54
|
+
"status": "outside_vault",
|
|
55
|
+
"reason": "renewal_managed_by_merchant",
|
|
56
|
+
"requirements": [
|
|
57
|
+
"verify_merchant_billing"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"limitations": [
|
|
62
|
+
"Only the listed request format is recognized; a recognized processor is not verified merchant coverage.",
|
|
63
|
+
"The adapter handles the Spreedly iframe v1 restricted endpoint for new credit cards through the encrypted relay.",
|
|
64
|
+
"The merchant environment and optional signed iframe session must remain valid. Expired signatures require a fresh merchant checkout.",
|
|
65
|
+
"Spreedly creates a payment-method token; the merchant still completes any gateway payment and authentication."
|
|
66
|
+
],
|
|
67
|
+
"unsupported_variants": [
|
|
68
|
+
{
|
|
69
|
+
"variant": "general_javascript_api",
|
|
70
|
+
"status": "unsupported",
|
|
71
|
+
"constraint": "direct_sdk",
|
|
72
|
+
"reason": "The general payment_methods.json endpoint is outside the reviewed native iframe path."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"variant": "saved_card_or_recache",
|
|
76
|
+
"status": "unsupported",
|
|
77
|
+
"constraint": "direct_sdk",
|
|
78
|
+
"reason": "Stored tokens and CVV-only recache requests are outside new-card tokenization."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"variant": "click_to_pay_or_bank_account",
|
|
82
|
+
"status": "unsupported",
|
|
83
|
+
"constraint": "direct_sdk",
|
|
84
|
+
"reason": "Click to Pay and bank-account request shapes require separate validation."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"variant": "gateway_purchase_or_distribution",
|
|
88
|
+
"status": "unsupported",
|
|
89
|
+
"constraint": "direct_sdk",
|
|
90
|
+
"reason": "Gateway transactions and payment-method distribution are outside the card tokenization adapter."
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"processor_amount": "none",
|
|
94
|
+
"challenge_surface": "merchant_browser",
|
|
95
|
+
"merchant_confirmation_required": true,
|
|
96
|
+
"live_validation": "not_established_by_catalog",
|
|
97
|
+
"sources": [
|
|
98
|
+
"src/definitions.js",
|
|
99
|
+
"src/operations.js",
|
|
100
|
+
"src/backend.js",
|
|
101
|
+
"src/spreedly.js",
|
|
102
|
+
"../checkout/src/prepared-processor.ts"
|
|
103
|
+
]
|
|
104
|
+
},
|
|
8
105
|
{
|
|
9
106
|
"psp": "shopify",
|
|
10
107
|
"status": "supported",
|