@agent-cards/sdk 0.23.28 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/PREFLIGHT.md +7 -1
- package/README.md +197 -102
- package/dist/aci.d.ts +52 -22
- package/dist/aci.js +79 -15
- package/dist/adyen-merchant-hosted.generated.d.ts +2 -2
- package/dist/adyen-merchant-hosted.generated.js +586 -55
- package/dist/agent-amount.generated.js +1 -1
- package/dist/agentcard.d.ts +4 -5
- package/dist/agentcard.js +4 -5
- package/dist/amadeus.d.ts +9 -3
- package/dist/amadeus.js +33 -4
- package/dist/api-module.d.ts +1 -7
- package/dist/api-module.js +3 -5
- package/dist/{voice-retry.js → api-retry.js} +1 -1
- package/dist/api-types.d.ts +53 -0
- package/dist/{voice-types.js → api-types.js} +7 -2
- package/dist/approvals.d.ts +166 -0
- package/dist/approvals.js +213 -0
- package/dist/aurus.d.ts +33 -0
- package/dist/aurus.js +75 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/buy.d.ts +20 -101
- package/dist/buy.js +19 -74
- package/dist/capabilities.generated.js +1 -1
- package/dist/card-fields.generated.js +2864 -249
- package/dist/cardlink-vpos.d.ts +43 -0
- package/dist/cardlink-vpos.js +90 -0
- package/dist/cdp.d.ts +3 -13
- package/dist/cdp.js +244 -175
- package/dist/checkout-com.generated.js +5 -1
- package/dist/client.d.ts +170 -22
- package/dist/client.js +281 -40
- package/dist/creditguard.generated.d.ts +4 -4
- package/dist/cybersource-flex.generated.d.ts +39 -1
- package/dist/cybersource-flex.generated.js +100 -11
- package/dist/datatrans.generated.js +22 -1
- package/dist/eghl.d.ts +40 -0
- package/dist/eghl.js +72 -0
- package/dist/elavon-converge.generated.js +5 -3
- package/dist/gmo.generated.js +7 -2
- package/dist/hold.d.ts +8 -0
- package/dist/hold.js +43 -2
- package/dist/hosted-entry.js +4 -0
- package/dist/index.d.ts +9 -15
- package/dist/index.js +6 -10
- package/dist/lifecycle.d.ts +9 -61
- package/dist/lifecycle.js +24 -10
- package/dist/merchant-card-endpoints.generated.d.ts +6 -1
- package/dist/merchant-card-endpoints.generated.js +344 -19
- package/dist/merchant-hosted.d.ts +8 -1
- package/dist/nike-order.d.ts +51 -0
- package/dist/nike-order.js +81 -0
- package/dist/oceanpayment.d.ts +38 -0
- package/dist/oceanpayment.js +70 -0
- package/dist/paddle-tokenex.generated.js +111 -11
- package/dist/payplug.d.ts +41 -0
- package/dist/payplug.js +71 -0
- package/dist/payrails.generated.js +33 -8
- package/dist/pre-claim.d.ts +11 -0
- package/dist/pre-claim.js +130 -7
- package/dist/preflight-capabilities.generated.d.ts +0 -4
- package/dist/preflight-capabilities.generated.js +0 -5
- package/dist/preflight-catalog.json +200 -6
- package/dist/preflight-playwright.d.ts +2 -2
- package/dist/preflight-playwright.js +63 -14
- package/dist/preflight-schemas.json +18 -0
- package/dist/preflight.generated.d.ts +5 -4
- package/dist/preflight.generated.js +63 -3
- package/dist/preparation.d.ts +7 -0
- package/dist/preparation.js +21 -0
- package/dist/prepared-processor.d.ts +18 -5
- package/dist/prepared-processor.js +48 -8
- package/dist/primer.generated.js +2889 -268
- package/dist/processout.generated.d.ts +61 -0
- package/dist/processout.generated.js +577 -0
- package/dist/requests.js +1 -1
- package/dist/shiji-sts.generated.js +111 -11
- package/dist/stripe-checkout.generated.js +2761 -319
- package/dist/substitutions.generated.js +553 -26
- package/dist/tap-payments.generated.js +111 -11
- package/dist/twoc2p.generated.js +111 -11
- package/dist/url-masks/bluesnap.d.ts +2 -0
- package/dist/url-masks/bluesnap.js +15 -0
- package/dist/url-masks/oceanpayment.d.ts +2 -0
- package/dist/url-masks/oceanpayment.js +13 -0
- package/dist/url-masks/payplug.d.ts +2 -0
- package/dist/url-masks/payplug.js +13 -0
- package/dist/url-masks/vtex_payments.d.ts +2 -0
- package/dist/url-masks/vtex_payments.js +12 -0
- package/dist/url-masks.generated.d.ts +1 -1
- package/dist/url-masks.generated.js +6 -2
- package/dist/verifone.generated.js +42 -2
- package/dist/vtex-payments.generated.d.ts +127 -0
- package/dist/vtex-payments.generated.js +544 -0
- package/dist/webhooks.d.ts +2 -2
- package/dist/webhooks.js +2 -2
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +6 -8
- package/dist/languages.d.ts +0 -23
- package/dist/languages.js +0 -76
- package/dist/voice-pkce.d.ts +0 -49
- package/dist/voice-pkce.js +0 -147
- package/dist/voice-stream.generated.d.ts +0 -118
- package/dist/voice-stream.generated.js +0 -170
- package/dist/voice-types.d.ts +0 -735
- package/dist/voice.d.ts +0 -373
- package/dist/voice.js +0 -815
- package/readme.test.mjs +0 -53
- /package/dist/{voice-retry.d.ts → api-retry.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,90 @@ An unreleased change waits as a file of its own in `changes/` (`changes/README.m
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.24.1
|
|
8
|
+
|
|
9
|
+
- Pause eGHL's payment page entry for the cardholder's device. This build declares `eghl_hosted_payment_page`, and for a company the API turns the lane on for, Agentcard's own for now, it pauses the merchant's entry, a `GET` of `https://securepay.e-ghl.com/IPG/payment.aspx` whose query names the payment, creates a `hosted_form` authorization for it, and fails every post a page it watches sends to eGHL's hosts, so eGHL never receives the card your agent typed. The entry names its amount, and the API answers `amount_mismatch` for any other. No eGHL payment completes yet: while the relay route stays closed the API answers every create with `503 eghl_relay_unavailable`, which is expected, not a setup error.
|
|
10
|
+
|
|
11
|
+
- Refuse Frisbii Checkout's two other card requests for a company Agentcard turned Frisbii on for: a stored card's token (`https://card.reepay.com/v1/token/cof/`, or `card.frisbii.com`) and Click to Pay (`/v1/token/create_click_to_pay`). The SDK now holds both and fails them in your browser before anything is created, whatever their body, as it already did for any body on `/v1/token/?session=<id>` other than the page's own card body. Agentcard pays a Frisbii page only with the cardholder's Vault card.
|
|
12
|
+
|
|
13
|
+
- Pause Paystack's hosted checkout charge for the cardholder's device, for a company Agentcard turned Paystack on for. The SDK declares `paystack_pinned_key` and pauses the card page's form `POST` to `https://standard.paystack.co/charge/`; the cardholder's device encrypts the real card under Paystack's pinned key and sends the charge itself. The charge names no price, so `authorize()` needs `amount` and `currency` above zero (`AmountRequiredError` otherwise).
|
|
14
|
+
|
|
15
|
+
- Pause Viva Wallet's Smart Checkout card request for the cardholder's device, for a company Agentcard turned Viva Wallet on for. Viva's checkout page (`https://www.vivapayments.com/web2?ref=<order code>`, where a Viva payment link sends a shopper) posts the card as JSON to `https://www.vivapayments.com/web2/checkout/v2/chargetokens` (`demo.vivapayments.com` in test) when the shopper presses Pay. The sync now also asks for `capabilities=viva_smart_checkout_chargetoken`, and the API serves Viva Wallet's recognizer only for a company Agentcard turned Viva Wallet on for. The SDK pauses only the page's own card body at that exact URL: a body that asks Viva to keep the card, pays with a stored card, takes Viva's currency conversion or is the page's second try after a decline fails in your browser before anything is created. The cardholder's device sends the card through Agentcard's checkout relay with the real card, and the page gets Viva's single-use charge token, which it charges itself. The body names its amount, so pass the same `amount` and `currency`: a pair that differs is refused before anything is created. A Viva Wallet payment also needs the matching API and Vault releases. Viva Wallet stays off for every company Agentcard has not turned it on for.
|
|
16
|
+
|
|
17
|
+
- The SDK declares `aurus_one_time_token`. For a company Agentcard turns Aurus on for, it pauses the card request Aurus Pay's ecom card frame sends to `pecst<NN>.aurusepay.com/storeservices/ecom/oneTimeToken`, only when Aurus's own card frame sent it, and `authorize()` needs `amount` above zero and `currency` for it ("An Aurus payment request names no amount"). No Aurus payment is approved yet.
|
|
18
|
+
|
|
19
|
+
- Pause the card request LEGO's checkout sends to its own server. Its checkout on `www.lego.com` encrypts the card with adyen-web and posts it, in the GraphQL mutation `AddAdyenPayment`, to `https://www.lego.com/checkout/api/graphql/AddAdyenPayment`. The adapters now pause that request and refuse it as `unsupported_checkout` while the new profile, `lego_checkout_add_adyen_payment`, is in `observe`, so the agent's dummy card never reaches the store. A body that keeps the card for later or names a stored card is aborted, and the checkout's other operations, which carry no card, pass as before.
|
|
20
|
+
|
|
21
|
+
- The payment core knows eGHL's hosted payment page (securepay.e-ghl.com), the gateway behind many Malaysian stores and eGHL's own Shopify app. Its recognizer sits behind the `eghl_hosted_payment_page` capability, which this build declares (the eGHL entry above). Its entry names the payment and the customer in its query, which every URL the SDK writes into an event or an error already drops, so no mask is added.
|
|
22
|
+
|
|
23
|
+
- Pause the card request of Frisbii Checkout, the hosted payment page Frisbii (formerly Reepay) opens on `checkout.reepay.com` or `checkout.frisbii.com`, for the cardholder's device, for a company Agentcard turned Frisbii on for. The page posts the card as JSON with the merchant's public key to `https://card.reepay.com/v1/token/?session=<id>` (or `card.frisbii.com`). The sync now also asks for `capabilities=frisbii_card_token`, and the API serves Frisbii's recognizer only for a company Agentcard turned Frisbii on for. The SDK pauses only the page's own card body at that exact URL, and any other body there, one that keeps the card on file included, fails in your browser before anything is created. A stored card's token (`/v1/token/cof/`) and Click to Pay (`/v1/token/create_click_to_pay`) are refused, as the Frisbii entry above says. Pass `amount` and `currency`, above zero, equal to the page's own total: without them `authorize()` throws `AmountRequiredError` ("A Frisbii payment request names no amount"), and the API refuses an amount the page's 3-D Secure data does not name. A Frisbii payment also needs the matching Vault release. Frisbii stays off for every company Agentcard has not turned it on for.
|
|
24
|
+
|
|
25
|
+
- Pause MONEI's card frame request for the cardholder's device, for a company Agentcard turned MONEI on for. MONEI's payment page (`https://secure.monei.com/payments/<id>`, where a store on MONEI Payments sends its shopper) posts the card as JSON with the payment's id to `https://api.monei.com/v1/tokens`. The sync now also asks for `capabilities=monei_card_token`, and the API serves MONEI's recognizer only for a company Agentcard turned MONEI on for. The SDK pauses only the frame's own card body at that exact URL: MONEI's account flow, Click to Pay and a wallet sent to the same URL fail in your browser before anything is created. The request names no amount, so pass `amount` and `currency`, above zero, equal to the payment's own total: without them `authorize()` throws `AmountRequiredError`, and the API refuses any other amount after reading MONEI's record of the payment. A MONEI payment also needs the matching Vault release. MONEI stays off for every company Agentcard has not turned it on for.
|
|
26
|
+
|
|
27
|
+
- Pause Cardlink's VPOS entry for the cardholder's device. This build declares `cardlink_vpos_hosted_payment_page`, and for a company the API turns the lane on for, Agentcard's own for now, it pauses the merchant's signed entry, a form post to `https://<host>/vpos/shophandlermpi` on `vpos.eurocommerce.gr`, `ecommerce.cardlink.gr` or `www.alphaecommerce.gr`, creates a `hosted_form` authorization for it, and fails every other post a page it watches sends to those hosts, so the VPOS never receives the card your agent typed. The entry names its amount in euros, and the API answers `amount_mismatch` for any other. No Cardlink payment completes yet: while the relay route stays closed the API answers every create with `503 cardlink_vpos_relay_unavailable`, and once it opens it refuses every entry with `seller_unreviewed` until Agentcard reviews the merchant's mid on its host. Both refusals are expected, not a setup error.
|
|
28
|
+
|
|
29
|
+
- The SDK pauses the card request Checkout.com's card fields send to your account's own subdomain, its base URL prefix. Frames sends the card to `/tokens` on the prefix's API host, such as `4k2njisl.api.checkout.com`, when you set `baseURLPrefix`. Flow sends it to `/cag/tokens`, then `/tokens`, on `devices.api.checkout.com` or `4k2njisl.devices.api.checkout.com` when its payment session turns on Checkout.com's devices API, as the hosted payments page does. Before this release those requests reached Checkout.com unpaused, carrying the placeholder card. Any alphanumeric prefix works, on the production hosts and their `.sandbox.checkout.com` counterparts, and `prepare({ psp: 'checkout_com' })` binds these requests too. An SDK that calls `vault.syncRegistry()` pauses them once Agentcard's API serves the hosts; `prepare()` on them needs this release, and the cardholder's approval page sends the card there from Agentcard's next Vault release.
|
|
30
|
+
|
|
31
|
+
- `attachToCdp` keeps a ready `prepare()` when the checkout page moves within its own document and keeps the same origin, path and query: a `history.replaceState` to the page's own URL, which single-page checkouts call after each server action, or a change to the URL's `#` fragment alone. A history update to another path or query still ends the preparation with `merchant_document_changed`.
|
|
32
|
+
|
|
33
|
+
## 0.24.0
|
|
34
|
+
|
|
35
|
+
### Upgrading from 0.23.28
|
|
36
|
+
|
|
37
|
+
- **Voice approval leaves this package, and page approval moves to `agentcard.approvals`.** `agentcard.voice` is gone, and so is the `voice` option on `new Agentcard()`. The four verbs a purchase approved on Agentcard's page needs keep their inputs and answers under `agentcard.approvals`: `voice.authorizations.create` is `approvals.create`, `request: 'sandbox'` included, `voice.authorizations.get` is `approvals.get`, `voice.authorizations.cancel` is `approvals.cancel`, and `voice.awaitResult` is `approvals.awaitResult`. Every approval runs on Agentcard's page, so a client names no approval posture, and the return link comes from the create's `return_url` alone. `awaitResult` waits 60 seconds unless `timeout_ms` names another deadline.
|
|
38
|
+
|
|
39
|
+
- These `voice` verbs go with no replacement: `connect`, `completeConnect`, `exchange`, `awaitConnected`, `disconnect`, `sessions.get`, `people.get`, `authorizations.setCard`, `approvals.approvalUrl`, `challenge`, `challengeForHost`, `stream`, `appKeys.register`, `appKeys.revoke`, `reset`, `actions.propose`, `actions.get`, `actions.awaitDone` and `languages()`. The approval link is the `approval_url` the create and every open read carry. A read no longer types `intent`, `intent_hash`, `interaction_evidence`, `delivery_channel`, or the processor's answer that `controller.resume` replayed. `buy.confirm` takes no `approval`, a turn never answers `needs_approval`, and `buy.approveByVoice` is gone; `authorization_id` on `buy.confirm` works as before. `attachToCdp` takes neither `pauseOnly` nor `onPaused`, and the controller has no `resume`. `CHECKOUT_AUTHORIZATION_EVENT_TYPES` no longer names `checkout_authorization.voice_dispatched`. `ApiTransport` loses `languages` and `pollTimeoutMs`.
|
|
40
|
+
|
|
41
|
+
- Removed exports: `VoiceModule`, `checkoutOriginOf`, `bundleOf`, `streamAddress`, `Languages`, `readReturnLink`, `openStream`, `streamBuffer`, `isBuyNeedsApproval`, `isBuyVoiceUnsupported`, `VOICE_EXECUTION_UNSUPPORTED`, and the types `VoiceOptions`, `VoiceTransport`, `Language`, `LanguageInfo`, `PkceCrypto`, `Lang`, `VoiceAsk`, `ApprovalPosture`, `Action`, `ConnectInput`, `ConnectResult`, `Connected`, `Person`, `Proposed`, `Done`, `ActionState`, `VoiceResetInput`, `VoiceChallenge`, `Verdict`, `AuthorizationDetail`, `Exchanged`, `ExchangeInput`, `Revoked`, `DeliveryChannel`, `InteractionEvidence`, `Intent`, `ApprovalRequestFields`, `SessionState`, `ReturnLink`, `VoiceResetOutcome`, `VaultSessionStep`, `HostApprovalBundle`, `AppVoiceKeyDescription`, `HardwareAttestation`, `RegisteredAppVoiceKey`, `RevokedAppVoiceKey`, `Hearing`, `StreamFormat`, `StreamHandle`, `StreamInput`, `StreamVerdict`, `ChannelKind`, `BuyApproval`, `BuyVoiceDeclineCode`, `BuyNeedsApproval`, `BuyVoiceUnsupported`, `BuyVoiceTurn`, `BuyApproveByVoiceInput`, `PausedCheckout` and `ResumeResult`. `SANDBOX_REQUEST`, `CANCEL_REASONS` and the types `CreateAuthorizationInput`, `Authorization`, `AuthorizationResult`, `Cancelled`, `PayingCard` and `ChoosableCard` stay, beside the new `ApprovalsModule` and `AuthorizationFields`. The checkout module, `buy.ask`, `buy.confirm`, `buy.conversation`, the CDP and Playwright adapters, the registries and the webhooks work as before.
|
|
42
|
+
|
|
43
|
+
- TypeScript: `MerchantHostedSubstitutions.path` is now `ProfilePathStep[]`. A step is a `JsonPathStep` or `{ text: 'json' }`, the step into a string that holds JSON text, and both new types are exported, `JsonTextStep` and `ProfilePathStep`. Code that reads each step as a string or a number needs the new case. `CardRequestHold` gains `covers`.
|
|
44
|
+
|
|
45
|
+
- Nike's card frame profile, `nike_paymentcc_store`, takes a Mastercard only: the frame's store post must name `MASTERCARD`, the one code Nike's recorded purchase shows. Type a Mastercard-range placeholder into Nike's frame. A placeholder the frame names `VISA` or any other code is no longer Nike's reviewed request, so the adapters refuse it with reason `unrecognized_payment_endpoint`. The profile stays in observe.
|
|
46
|
+
|
|
47
|
+
- Keep a cart's unquoted fees unquoted. `BuyCart.serviceFeesCents` is now `null` while the store has not quoted its fees, and the new `serviceFeesStatus` says `pending`. Before, the client read a missing amount as `0`, so an app could not tell fees still to come from no fees at all. A quoted amount reads `known`, and anything else reads `unknown` with a `null` amount. `ask()`, `conversation()` and the carts that come back with an error read fees the same way.
|
|
48
|
+
|
|
49
|
+
### New
|
|
50
|
+
|
|
51
|
+
- Pause iyzico's Checkout Form card payment for the cardholder's device, for a company Agentcard turned iyzico on for. iyzico's hosted Checkout Form (on `cpp.iyzipay.com`, where iyzico's Shopify app sends the buyer, and the form iyzico's WooCommerce plugin renders) posts the card as JSON to `https://api.iyzipay.com/payment/iyzipos/checkoutform/auth/ecom`, or to `.../initialize3ds/ecom` when 3-D Secure runs, under the form's `X-IYZI-TOKEN`. The sync now also asks for `capabilities=iyzico_checkout_form`, and the API serves iyzico's recognizer only for a company Agentcard turned iyzico on for. The SDK pauses only the form's own payment with a new card at those exact URLs: a saved card, a card the form would keep on file, an installment plan and a currency conversion fail in your browser before anything is created. A payment that names no `buyerProtected` pauses too, the way the form sends it for a guest on a page without iyzico's card storage script (`window.iyziUcsInit`), an iyzi.link payment link among them; one whose `buyerProtected` is anything but `false` fails in your browser, since buyer protection keeps the card with iyzico. The cardholder's device sends the payment to iyzico itself with the real card, and the form gets iyzico's answer: the payment done, or the bank's 3-D Secure page, which the form then runs in the agent's browser, where a challenge needs a person at that browser. The payment names its price but not its currency, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created, and the API refuses a pair whose amount is not the payment's price. An iyzico payment also needs the matching API and Vault releases. iyzico stays off for every company Agentcard has not turned it on for.
|
|
52
|
+
|
|
53
|
+
- Pause Paymentwall's card request for the cardholder's device, for a company Agentcard turned Paymentwall on for. Paymentwall's card form, on Paymentwall's hosted checkout or on a merchant's own page, sends the card as a form post to `https://pwgateway.com/api/token` under the merchant's public key, or to `https://api.paymentwall.com/api/brick/token` under a test key, and Paymentwall answers with a one-time token the checkout charges afterwards. The sync now also asks for `capabilities=paymentwall_card_token`, and the API serves Paymentwall's recognizer only for a company Agentcard turned Paymentwall on for. The SDK pauses only the card form's own request at those exact URLs: a stored card's security code, a Google Pay token, a card brand picked from the page's own list and any other body there fail in your browser before anything is created. The cardholder's device sends the request to Paymentwall itself with the real card, and the page gets Paymentwall's token. Paymentwall's request names no price, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created. The API pays only a Paymentwall merchant Agentcard reviewed for the checkout page the request comes from. Matching API and Vault releases are required. Paymentwall stays off for every company Agentcard has not turned it on for.
|
|
54
|
+
|
|
55
|
+
- Pause BlueSnap's Hosted Payment Fields for the cardholder's device, for a company Agentcard turned BlueSnap on for. The card number, expiry and code frames each send their own field as a JSON `PUT` to the merchant's payment-fields token, `https://ws1.bluesnap.com/services/2/payment-fields-tokens/<token>` (`ws2` for a token ending `_2`, `sandpay.bluesnap.com` in BlueSnap's sandbox). The sync now also asks for `capabilities=bluesnap_hosted_payment_fields`, and the API serves BlueSnap's recognizer only for a company Agentcard turned BlueSnap on for. The SDK pauses the card number frame's `PUT`, the cardholder's device sends the whole card in that one request, and the page gets BlueSnap's card data. The SDK holds the expiry and code frames' own `PUT`s and answers them with that answer, so the placeholder values never reach BlueSnap; they fail when the card number request fails, or when none begins within five seconds. A second card number request on the same token (`split_card_reused`), a saved card's request (`bluesnap_saved_card`) and anything else on the token's URL fail in your browser, and the page's own retry of the card number request while the cardholder is still deciding gets the approval's answer. The store's server charges the token afterwards and can ask BlueSnap to keep the card, so a live payment takes only a card the person stored (`card_not_stored`), and the approval says the store can keep it. The request names no price, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created. The token is the request's only credential, so `redactUrl` reads it as `{token}` in every event, error and URL the SDK reports. Matching API and Vault releases are required. BlueSnap stays off for every company Agentcard has not turned it on for.
|
|
56
|
+
|
|
57
|
+
- Pause the card post of Oceanpayment's hosted payment page for the cardholder's device, for a company Agentcard turned Oceanpayment on for (dark launch). The page, where Oceanpayment's Shopify redirect app sends the buyer after Shopify's Pay now, submits its card form natively to `https://secure.oceanpayment.com/gateway/sendPay;jsessionid=<session>` with the card in clear. The sync now also asks for `capabilities=oceanpayment_hosted_payment_page`, and the API serves Oceanpayment's recognizer only for a company Agentcard turned Oceanpayment on for. The SDK pauses only that post, exactly as the page's form action writes it, and aborts every other post to `secure.oceanpayment.com` and `test-secure.oceanpayment.com` as `unsupported_checkout` with reason `processor_card_page`, Cardinal's device-data call among them, so the agent's placeholder never reaches Oceanpayment; the page's own GETs continue. The cardholder's device writes the real card into the paused post and sends it through Agentcard's checkout relay. The post names no price, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created. The API takes only a test payment on Oceanpayment's sandbox today, since the post names neither the merchant nor the amount, and no answer is recorded as paid yet: a 4xx is a refusal, and every other answer waits as unknown for a person to settle. The session in the path names the payment the page holds, so `redactUrl` reads it as `{session}` in every event, error and URL the SDK reports, as in `https://secure.oceanpayment.com/gateway/sendPay;jsessionid={session}`. Matching API, relay and Vault releases are required. Oceanpayment stays off for every company Agentcard has not turned it on for.
|
|
58
|
+
|
|
59
|
+
- Pause VTEX Payments' card post for the cardholder's device, for a company Agentcard turned VTEX on for, only through a checkout the cardholder approved before Pay. Ollie's headless checkout, which some VTEX stores run, posts the card as JSON to the store's own VTEX vault, `https://<account>.vtexvault.com/api/payments/transactions/<id>/payments`, and gives the post 12 seconds. The sync now also asks for `capabilities=vtex_payments_card_payment`, and `prepare({ psp: 'vtex_payments', environment: 'production' })` names VTEX's one environment. The claim binds the first post by its shape; Ollie sends the same post again on a non-OK answer or a network error, then once more to `api.vtexvault.com`, and each of those fails in your browser on the spent approval, so one approval sends the card once. A post with no preparation fails in your browser before anything is created (`PreparationRequiredError`). The post names its price, which the cardholder approves, and VTEX answers it with a 201 and no body, so the payment's result comes from the checkout's next step, not from that answer. VTEX's payments endpoint takes no authentication, so the 32 hex digits after `/transactions/` on `<account>.vtexvault.com` are all a card post to that payment needs: `redactUrl` reads them as `{transaction}` in every event, error and URL the SDK reports. A payment also needs the matching API and Vault releases and a store Agentcard reviewed. VTEX Payments stays off for every company Agentcard has not turned it on for.
|
|
60
|
+
|
|
61
|
+
- Answer Ollie's VTEX card post inside the 12 seconds Ollie's checkout gives it. A prepared VTEX authorization is read every 500 ms for those 12 seconds, so VTEX's answer reaches the checkout within half a second of the cardholder's device recording it. The create names how long ago the post paused on your machine's clock (`paused_ms`), and the API counts 8 of the 12 seconds from that pause on its own clock: a post the cardholder's device has not sent by then is refused with `vtex_payments_post_timed_out` and nothing sent, at the create before any row or as a decline once the row exists, and a create refused that way retires its preparation. A paused post the device has not sent 8 seconds after the pause fails in your browser with nothing sent once the API confirms the card never left (`vtex_payments_send_window_closed`); while the device may be sending, the post keeps waiting for its answer. `authorize()` throws `CheckoutPreparationError` with either reason, never `CheckoutApiError` or `ApprovalDeclinedError`. A direct `authorize()` of a VTEX preparation must name `pausedAt`, which the adapters fill: without it the call throws before any create, and the preparation stays unspent for a call that names it. A post Ollie's checkout aborts while it waits ends the attempt with no second create, as an unknown outcome when the card may have left. `prepare({ psp: 'vtex_payments' })` passes on by name the API's refusals before any preparation exists: `processor_unavailable`, `live_host_on_sandbox_row`, `merchant_profile_mismatch`, `unsupported_currency` and `amount_required`.
|
|
62
|
+
|
|
63
|
+
- Pause USAePay's Pay.js card frame request for the cardholder's device, for a company Agentcard turned USAePay on for. USAePay's card frame (`https://www.usaepay.com/js/v2/card.html`, which a merchant's checkout page mounts) posts the card as JSON to `https://www.usaepay.com/api/v2/pub/payment_keys` (`secure.usaepay.com` alike, `sandbox.usaepay.com` in test) under the merchant's public key in its `Authorization`. The sync now also asks for `capabilities=usaepay_payment_key`, and the API serves USAePay's recognizer only for a company Agentcard turned USAePay on for. The SDK pauses only the frame's own card body at that exact URL: a Google Pay or Apple Pay token and a bank account sent to the same URL fail in your browser before anything is created. The cardholder's device sends the card through Agentcard's checkout relay with the real card, and the frame gets USAePay's single-use payment key, which the merchant's server charges afterwards. The request names no amount, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created. A USAePay payment also needs the matching API and Vault releases. USAePay stays off for every company Agentcard has not turned it on for.
|
|
64
|
+
|
|
65
|
+
- Pay a ProcessOut checkout, for the company Agentcard turned ProcessOut on for (dark launch). The store's page hands its card to ProcessOut.js, whose card frame on `js.processout.com` posts it to `https://api.processout.com/cards` under the store's project id and calls the page's error callback 20 seconds after the page asks it for a token, too soon for an approval after that press. So the SDK sends the card only through `prepare({ psp: 'processout', environment: 'production' })` (`'sandbox'` for a `test-proj_` project), before the press; without one, the SDK refuses the request before it asks the API, and sends nothing. The sync now also asks for `capabilities=processout_card_token`. Live and sandbox projects share one host, so the SDK binds the press's request to the approval by its project's environment and its shape, never by the URL `prepare()` names. Once the cardholder approves, the request pauses, the cardholder's device sends the card to ProcessOut itself, and the frame receives ProcessOut's card token, rebuilt from the card facts the page reads, and nothing else. A refusal ProcessOut answers inside a 2xx never reaches the frame as a token. One approval sends one card request, and a request the cardholder's device has not sent 12 seconds after the pause fails before the card leaves, with `processout_send_window_closed`. ProcessOut's request names no amount, so the cardholder approves the `amount` and `currency` you pass, above zero; the API refuses a zero `amount` with `amount_required` and an environment other than your key's mode with `processout_environment_mismatch`, and `prepare()` names both. A live project pays only a store Agentcard has reviewed, at its reviewed page and under its reviewed name and project id. Agentcard has reviewed none yet, so `prepare()` on a live project fails with `unsupported_checkout` before anyone is asked. The API holds the reviewed stores, so a store Agentcard reviews later needs no new SDK. No ProcessOut payment has gone through this route yet. A payment also needs the matching API and Vault releases.
|
|
66
|
+
|
|
67
|
+
- Pause PayPlug's payment page link for the cardholder's device, for a company Agentcard turned PayPlug on for, Agentcard's own for now. The sync now also asks for `capabilities=payplug_hosted_payment_page`. The SDK pauses the merchant's redirect to `https://secure.payplug.com/pay/<payment id>` (or `/pay/test/<payment id>` for a test payment), creates a `hosted_form` authorization for it, and fails every post a page it watches sends to PayPlug's page host, so PayPlug never receives the card your agent typed. The link names no amount: `authorize()` throws `AmountRequiredError` without your `amount` and `currency`, above zero, and the API answers `amount_required` for any currency but euros. One PayPlug payment takes one authorization across your company: a second one while the first awaits answers `duplicate_submission`, and one for a payment a card may already have gone to answers `payplug_payment_already_sent`. The link opens that payment's page and pays it, so `redactUrl` reads its id as `{payment}` in every event, error and URL the SDK reports, as in `https://secure.payplug.com/pay/{payment}`. No PayPlug payment completes yet: the API refuses every PayPlug link with `seller_unreviewed` until Agentcard reviews the name and the PayPlug account a merchant's PayPlug page shows, so that refusal is expected, not a setup error. Matching API and Vault releases are required. PayPlug stays off for every company Agentcard has not turned it on for.
|
|
68
|
+
|
|
69
|
+
- Pause the card request teenage engineering's checkout sends to its own server. Its Centra checkout on `teenage.engineering` runs Adyen's Drop-in and posts adyen-web's encrypted card, as `paymentMethodSpecificFields`, to `https://teenage.engineering/_api/mw/selections/<selection>/payment2`. The adapters now pause that request and refuse it as `unsupported_checkout` while the new profile, `teenage_engineering_centra_payment`, is in `observe`, so the agent's dummy card never reaches the store. The order form's own post to the same path, which carries no card, passes as before. A body that keeps the card for later, names a stored card or subscription contracts, or carries the card on the initiate call is aborted.
|
|
70
|
+
|
|
71
|
+
- Pause the card request SCHEELS' and Buff's checkouts send to their own servers. SCHEELS' page posts adyen-web's state as JSON text inside its own body, `state`, to `https://apihub.scheels.com/frontastic/action/cart/setAdyenCreditCard`; Buff's Magewire checkout posts it as the `placeOrder` argument to `https://www.buff.com/us/magewire/post/livewire/message/checkout.payment.methods.adyen_cc`. The adapters now pause each request and refuse it as `unsupported_checkout` while the new profiles, `scheels_frontastic_adyen_card` and `buff_magewire_adyen_cc`, are in `observe`, so the agent's dummy card never reaches either store. A profile's rules now read inside JSON text a body carries, and only text written exactly as `JSON.stringify` or PHP's `json_encode` (default flags) writes it, as Buff's server does: anything else is aborted.
|
|
72
|
+
|
|
73
|
+
- Pause the card request Philipp Plein's checkout sends to its own server. Plein's SiteGenesis page writes adyen-web's state as JSON text into one field of its billing form and posts the form to `https://www.plein.com/us/billing/`. The adapters now pause that form post and refuse it as `unsupported_checkout` while the new profile, `plein_sfcc_billing_form`, is in `observe`, so the agent's dummy card never reaches the store. A profile's rules now read a form body written exactly as a browser writes it, and an observe event reports a form's shape by its field names. Plein's page names its total only in an analytics block, so the profile cannot be paid until a reviewed rule reads it.
|
|
74
|
+
|
|
75
|
+
- Hold Nike's order to the amount the cardholder approved. Once an adapter asks the cardholder to pay through Nike's card frame profile, `nike_paymentcc_store`, it holds every request to `api.nike.com`. `attachToCdp` holds them in every frame it arms from the attach on, so a page already loaded when the cardholder is asked is held too; at the ask it also arms every other page and frame of the browser context then open, and the browser target, which reaches a tab or shared worker the checkout did not open once it loads after the ask. `attachToPlaywright` holds them with a route on the page's browser context, which reaches no shared or service worker. One order, `PUT /buy/checkouts/v3/<checkoutId>`, goes on unchanged, only when its `request.totals.total` and `request.currency` are the `approved` amount and the checkout still names that approval as under way, and after it only a byte-identical retry; a write whose path a server may read as under `/buy/checkouts/`, however it is spelled, is judged the same way. Every other request to `api.nike.com`, and any sent before the ask, continues untouched. An order that fails the amount rule, or comes while no approved amount was read, fails before it leaves, nothing is charged, a checkout still under way ends `failed` with reason `merchant_order_<why>`, and every later order under that approval fails too. A second order, or one after the checkout was cancelled, reconciled or retried, fails and leaves the state as it is. The events `merchant_order_released` and `merchant_order_refused` name the authorization and never the order. A browser, context, page or frame that cannot take the hold refuses the payment to Nike before anything is created. At the browser target, in the pages armed at the ask and on Playwright's context route, only the attachment that asked through Nike's profile last in that browser context, for any attempt, judges Nike's order; in the frames it arms, each `attachToCdp` attachment judges every order itself. The profile stays in observe.
|
|
76
|
+
|
|
77
|
+
- A card endpoint answer from `authorize()` (`CardEndpointReplay`) carries `approved`: the amount the cardholder approved, in the currency's smallest unit, with its currency, as the API's read names it. It is absent when the read names none.
|
|
78
|
+
|
|
79
|
+
- The preflight catalog names two more card forms. The card fields of every Bambora Custom Checkout 1 release on `libs.na.bambora.com` (rule `bambora-na-custom-checkout-fields`) name `bambora`, so a store that serves its own copy of Bambora's library, as Kent does, reads as Bambora and `supported` instead of naming no processor. The SDK pauses the same Bambora tokenization request as before. Worldpay's hosted payment pages under `/app/hpp/` and `/app/hpp-iframe/` on `payments.worldpay.com` (rule `worldpay-wpg-hosted-payment-page`), which Razer's checkout opens in a frame, name `worldpay` and read `unknown` with `processor_variant_unverified`, because the SDK takes over only Worldpay Access Checkout's card session. Both rule ids join the rule lists in `preflight-schemas.json`. BlueSnap leaves the catalog's exclusions, where it read `multi_request_tokenization_not_supported` with `human_checkout`, since the SDK now pauses its card fields. The catalog's `catalog_sha256` changes, as does the hash the Kernel kit's `inventory.json` carries; `catalog_version` stays `2026-09-15.1`.
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- Hold a card a processor encrypted in the page when the store sends it inside its own request. With `hold: { placeholderNumbers }`, the hold now also holds any request whose body carries Adyen's `encryptedCardNumber` (or the legacy `adyenjs_` ciphertext), Braintree's legacy client-side encryption or Worldline Connect's `encryptedCustomerInput`, wherever it goes. Adyen's card component in an Advanced (non-Sessions) integration, such as Salesforce Commerce's, sends the encrypted card to the store's own payment or order step, which no recogniser matched and which never carries the placeholder's digits, so Pay went through with nothing held. Such a request is held as `encrypted_card` (`store_card_post`) and only cancelled: no release sends it on, in sandbox or live (`encrypted_card_post`). `CardRequestHold.covers` lists the hold-only rules armed (`bolt`, `placeholder_card`, `encrypted_card`). Exported: `encryptedCardHoldRule`. No API or Vault release is needed.
|
|
84
|
+
|
|
85
|
+
- Attach on a checkout that runs a worklet. `attachToCdp` refused any page whose browser context held a CDP `worklet` target (an audio, paint, animation or layout worklet) with `CheckoutAttachmentError` reason `unavailable`, and a hold armed earlier failed with `browser_interception_unavailable` once one started. Shopify's checkout starts one in its web-pixel sandbox frames, so every attach on those checkouts failed. A worklet has no fetch, XHR, WebSocket or beacon, so it can send no card request, and the module it loads is fetched by its owning frame, through that frame's interception. The SDK now accepts it and releases it from its debugger wait without owning it. Auction and shared storage worklets still refuse the page. No API or Vault release is needed.
|
|
86
|
+
|
|
87
|
+
- Read a checkout that loads hundreds of its own scripts through to its card frames. `collectCheckoutSignals` and `inspectCheckout` charged every script, iframe and form location, and every frame's own address, against the signal and snapshot budgets in document order, top frame first. A store whose checkout loads a few hundred of its own scripts, as Magento's RequireJS checkouts do with one script per module, spent the whole snapshot budget before the read reached the card frame, so the result read `unknown` with `snapshot_limit` and named no processor. A location that no reviewed rule can match, such as a store's own script or an ad frame's address, is now skipped without counting against either budget, and the read reaches the card frames. A read the budgets still cut, such as a page that floods a processor's own host, still reads `unknown`, and one frame's read examines at most 16,384 elements. No API or Vault release is needed.
|
|
88
|
+
|
|
89
|
+
- Hand the page no bank or card name from a Payrails or Primer answer that could finish the card number. Both processors fill names from their own BIN tables, and with the BIN and the last four already on the page, a name holding the card's hidden middle digits completes the number. The Payrails answer the SDK rebuilds for the page now leaves out the issuer's name when it carries more than three digits, in any script, and the network, the card type and the country's name when they carry any; the token still reaches the page. A Primer token whose network and BIN table names carry more than three digits together never reaches the page: `authorize()` throws `PaymentOutcomeUnknownError` with reason `primer_token_unconfirmed`. Agentcard's API judges the answer the same way before it stores it, whatever SDK version asks, so this is a second check behind it.
|
|
90
|
+
|
|
7
91
|
## 0.23.28
|
|
8
92
|
|
|
9
93
|
- Hand the page no Juspay `/txns` answer whose bank redirect could carry the card. The page receives only Juspay's order id, transaction id, status and bank redirect, and the SDK now hands over an approved answer only when the redirect's pay/start link and its parameters name no 3-D Secure PaReq and hold no compressed value. A PaReq carries the card deflated, and any compressed value can, where a check that reads text never finds it. For any other answer, `authorize()` throws `PaymentOutcomeUnknownError` with reason `juspay_response_unconfirmed`, and the page never gets it. Agentcard's API checks the answer the same way before it stores it, whatever SDK version asks, so this is a second check behind it.
|
package/PREFLIGHT.md
CHANGED
|
@@ -219,9 +219,13 @@ Paygent (`paygent`) has no discovery rule in this table yet. Every Paygent card
|
|
|
219
219
|
|
|
220
220
|
Openpay (`openpay_bbva`) has no discovery rule in this table yet. Openpay merchants load `openpay.js` on pages that take no card, some on every page, so the script on a page is no evidence that a payment can be approved, and an Openpay checkout stays `unknown`. The direct SDK pauses the token request `openpay.js` sends to `api.openpay.mx/v1/<merchant id>/tokens` only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Openpay row of the [README](./README.md) processor table for what the SDK covers.
|
|
221
221
|
|
|
222
|
+
VTEX Payments (`vtex_payments`) has no discovery rule in this table yet. One class of vault hosts serves every VTEX store, so a rule would name every VTEX checkout while no VTEX payment can be approved yet. The direct SDK pauses the card post Ollie's checkout sends to `<account>.vtexvault.com/api/payments/transactions/<id>/payments` only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled.
|
|
223
|
+
|
|
224
|
+
ProcessOut (`processout`) has no discovery rule in this table yet. ProcessOut.js loads the same card frame from `js.processout.com` for every project, live or sandbox, so the frame on a page names no store Agentcard reviewed, and a ProcessOut checkout stays `unknown`. The direct SDK pauses the card request the frame sends to `api.processout.com/cards` only after `syncRegistry()`, only through a prepared checkout, and only for the company Agentcard turned ProcessOut on for. Read the ProcessOut row of the [README](./README.md) processor table for what the SDK covers.
|
|
225
|
+
|
|
222
226
|
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.
|
|
223
227
|
|
|
224
|
-
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
|
|
228
|
+
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, the card fields of every Bambora Custom Checkout 1 release on `libs.na.bambora.com`, 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 on `secure.worldpay.com` or `payments.worldpay.com`, identifies its processor and returns `unknown` with `processor_variant_unverified`. A new fingerprint never declares payment support by itself.
|
|
225
229
|
|
|
226
230
|
PayPal's legacy Hosted Fields (`paypal`) are identified from the card fields PayPal's JS SDK renders with `components=hosted-fields`: braintree-web builds whose version carries `-payments-sdk`, such as `3.32.0-payments-sdk-dev`, served from `assets.braintreegateway.com` as `hosted-fields-input-frame.min.html` and `hosted-fields-payments-sdk-tokenization-frame.min.html`. PayPal's frames send the card to PayPal, not to Braintree, so a page that shows them names `paypal` and returns `unknown` with `processor_variant_unverified`, and no braintree-web file from a `-payments-sdk` build counts as Braintree evidence. The SDK fails the card request those frames send; see the PayPal Hosted Fields row in the [README's processor table](./README.md#supported-processors).
|
|
227
231
|
|
|
@@ -361,6 +365,8 @@ Collect only the documented asset observations when using your own browser tools
|
|
|
361
365
|
|
|
362
366
|
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.
|
|
363
367
|
|
|
368
|
+
A script, iframe or form location, or a frame's own address, that no reviewed rule can match, such as a store's own scripts, counts against neither the signal limit nor the snapshot budget. A checkout that loads a thousand of its own scripts is still read through to its card frames. The collector examines at most `16384` script, iframe and form elements in one frame; a frame with more reads as `unknown` with `signal_limit`.
|
|
369
|
+
|
|
364
370
|
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.
|
|
365
371
|
|
|
366
372
|
## Validate without a purchase
|