@agent-cards/sdk 0.23.20 → 0.23.22
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 +55 -2
- package/PREFLIGHT.md +6 -0
- package/README.md +169 -5
- package/dist/amadeus-checkout.generated.d.ts +6 -1
- package/dist/amadeus-checkout.generated.js +26 -2
- package/dist/card-fields.generated.js +2341 -127
- package/dist/cdp.js +199 -28
- package/dist/client.d.ts +177 -9
- package/dist/client.js +387 -37
- package/dist/comgate.d.ts +50 -0
- package/dist/comgate.js +80 -0
- package/dist/creditguard.generated.js +4 -2
- package/dist/cse-body.js +11 -0
- package/dist/cybersource-secure-acceptance.generated.d.ts +1 -1
- package/dist/ebanx.d.ts +1 -1
- package/dist/ebanx.js +1 -1
- package/dist/eprotect.generated.d.ts +1 -1
- package/dist/eximbay.d.ts +46 -0
- package/dist/eximbay.js +69 -0
- package/dist/gmo.generated.js +7 -3
- package/dist/hipay.generated.d.ts +5 -5
- package/dist/hipay.generated.js +5 -2
- package/dist/hold.d.ts +1 -1
- package/dist/hold.js +10 -4
- package/dist/hosted-entry.d.ts +4 -0
- package/dist/hosted-entry.js +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/lifecycle.d.ts +9 -4
- package/dist/lifecycle.js +16 -4
- package/dist/paddle-tokenex.generated.js +7 -3
- package/dist/paygent.generated.d.ts +60 -0
- package/dist/paygent.generated.js +425 -0
- package/dist/payrails.generated.js +7 -3
- package/dist/payrexx.d.ts +91 -0
- package/dist/payrexx.generated.d.ts +91 -0
- package/dist/payrexx.generated.js +536 -0
- package/dist/payrexx.js +141 -0
- package/dist/pre-claim.d.ts +30 -1
- package/dist/pre-claim.js +257 -39
- package/dist/preflight-catalog.json +58 -0
- package/dist/preflight-schemas.json +4 -0
- package/dist/preflight.generated.js +26 -2
- package/dist/prepared-processor.d.ts +7 -2
- package/dist/prepared-processor.js +16 -2
- package/dist/primer.generated.js +2469 -255
- package/dist/przelewy24.d.ts +47 -0
- package/dist/przelewy24.js +88 -0
- package/dist/registry.d.ts +6 -5
- package/dist/registry.js +27 -7
- package/dist/shiji-sts.generated.js +7 -3
- package/dist/stripe-checkout.generated.js +896 -19
- package/dist/toast-seal.generated.d.ts +37 -0
- package/dist/toast-seal.generated.js +625 -0
- package/dist/toast.generated.d.ts +41 -0
- package/dist/toast.generated.js +113 -0
- package/dist/tokenex-iframe.d.ts +93 -0
- package/dist/tokenex-iframe.generated.d.ts +81 -0
- package/dist/tokenex-iframe.generated.js +403 -0
- package/dist/tokenex-iframe.js +195 -0
- package/dist/transbank.d.ts +45 -0
- package/dist/transbank.js +73 -0
- package/dist/twoc2p.generated.js +7 -3
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.23.22
|
|
6
|
+
|
|
7
|
+
- Keep a FastSpring checkout's session id out of your events and error messages. FastSpring's checkout, on every store's own host under `onfastspring.com`, sends the card to `/session/<id>/payment` (after `/popup-<name>` in a popup), and anyone who holds that session id can read the session's own page, its order and the token its requests carry. `redactUrl`, every event and every error message now show it as `{session}` on every FastSpring store host, as in `https://daisydisk.onfastspring.com/session/{session}/payment`. The SDK does not pause a FastSpring payment yet. No API or Vault release is needed.
|
|
8
|
+
|
|
9
|
+
- Recognize Toast's card request behind a dark launch. `syncRegistry()` now declares the `toast_pinned_key` capability (`SUPPORTED_CAPABILITIES`), and the API serves the recognizer only to an org Agentcard has enabled, so no other org's Toast checkout changes. For an enabled org, the frame's post to `https://payments.toasttab.com/v1/payment-methods` pauses when it is the guest card request under the key Agentcard pins; Apple Pay and Google Pay requests on the same URL continue untouched, and any other card request there fails with `request_without_card`. `authorize()` needs `amount` and `currency` above zero (`AmountRequiredError`), since Toast's request names no price. The cardholder's device seals the real card under Toast's key, and the SDK writes that sealed card over the agent's placeholder in `card.cardData` and changes no other byte before it continues the request; an approval whose served set is anything else fails as `PaymentOutcomeUnknownError` with reason `cse_substitutions_malformed`, and one read after its window as `cse_substitutions_expired`.
|
|
10
|
+
|
|
11
|
+
- Pay a Payrexx payment through the checkout relay, for a company Agentcard turns Payrexx on for (dark launch). A Payrexx merchant's page, `https://<merchant>.payrexx.com`, takes the card in Payrexx Pay's own card frame, which posts it to its own URL, `https://checkout.payrexx.com/?pspId=44&lang=<language>`. This build declares `payrexx_card_frame` on every sync, and the API serves the Payrexx entry only to a company Agentcard turned Payrexx on for, so every other company's Payrexx payments go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the frame's own one-time card request, and the API takes it only on a Payrexx page Agentcard reviewed, WWF Ost's (`wwfost.payrexx.com`) for now. It refuses any other page with `unsupported_checkout`, reason `payrexx_instance_unreviewed`, because a donation page may offer a monthly choice that it sends only in its own order request, which no card request shows, and the cardholder there would approve a one-time payment the page repeats. That request names the frame's total, but it only mints a token, and the merchant's page charges its own total later. So `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total the page shows, and the API holds it to the frame's figure exactly. The cardholder's device sends the card through the checkout relay, and the frame gets Payrexx's answer: the token, or the start of 3-D Secure. When 3-D Secure starts, the frame posts the card again for the authentication and, after the bank's challenge, for the post-authentication. The approval's read then names until when it covers those two posts (`TokenReplay.followUpsUntil`), and while the Vault page stays open the cardholder's device sends each one with the real card, with no second prompt, and the frame gets Payrexx's answer. A challenge opens on the merchant's page in the agent's browser and needs a person at that browser. Any other post of the card to the frame fails in the browser, so Payrexx never receives the dummy card, and the checkout reads `unsupported` with reason `unsupported_payrexx_card_resend` and holds, keeping the approval's state. While a send is out, a new card request fails in the browser with a `blocked` event, `a follow-up send is in flight`, which an EBANX send also raises now. A send that fails holds the checkout, even one the frame sends while the card request's answer is still landing, so the SDK refuses the frame's next card request, an EBANX one too. A Payrexx payment also needs the matching API, Vault and checkout relay releases.
|
|
12
|
+
|
|
13
|
+
- Pay a Paygent checkout, for a company Agentcard turned Paygent on for (dark launch). The merchant's page hands its card fields to Paygent's own `PaygentToken.js`, which sends them to `https://token.paygent.co.jp/n/token/request` (`https://sandbox.paygent.co.jp/n/token/request` in test) and gives up 35 seconds later, too soon for an approval after the press that sends it. So the SDK sends the card only through `prepare({ psp: 'paygent', environment: 'production' })` (`'sandbox'` for Paygent's test host), 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=paygent_token`. Once the cardholder approves, the press's request pauses, the cardholder's device sends the card to Paygent itself, and the page receives Paygent's single-use token and nothing else. One approval sends one card request: the SDK refuses a second press, and a request for a stored card's security code too. Paygent's request names no amount, so the cardholder approves the `amount` and `currency` you pass, and the API refuses a zero `amount` with `amount_required`, which `prepare()` names too. On Paygent's live host, Agentcard pays only a merchant it has reviewed, at its reviewed page, under its reviewed name, merchant id and token key, and in its currency (Tokyo Chinese School at `https://fundexapp.jp`, in yen, today). The API refuses any other with `unsupported_checkout`, or `unsupported_currency` for another currency, and `prepare()` fails with that code before anyone is asked. The API holds the reviewed merchants, so a merchant Agentcard reviews later needs no new SDK. The merchant's server runs 3-D Secure after the token, in your agent's browser. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
|
|
14
|
+
|
|
15
|
+
- Pause Eximbay's payment window (where Korean merchants send a buyer who pays with a foreign card) for the cardholder's device. The sync now also asks for `capabilities=eximbay_hosted_payment_page`, and the API serves Eximbay's recognizer only for a company Agentcard turned Eximbay on for. The SDK pauses the merchant's signed entry form to `https://secureapi.eximbay.com/Gateway/BasicProcessor.krp` (or `secureapi.test.eximbay.com` for a test merchant), which carries no card, as a `hosted_form` authorization, and answers the paused navigation with the `submitted_on_device` page once the cardholder's device has paid it. The merchant's page posts that form in the page or into a window it opens. `attachToCdp` pauses the post in the page, and the post into a window the page opened once it has armed that window. Eximbay's popup integration opens the window and posts the entry into it at once, so that entry can leave before the window is armed, as the entry on windows the merchant's page opens says: the SDK then fails the window's next post, the step, and the checkout reads `unsupported`, with no card sent. `attachToPlaywright` pauses only the post in the page, because Playwright does not route a window the page opens, so attach to an Eximbay checkout with `attachToCdp`. Every other post a page the SDK watches makes to Eximbay, the step that opens its window, the window's amount query, its lookup of the card's first eight digits and its card post, carries the card your agent typed or follows it: the SDK fails each one and reads `unsupported` with reason `processor_card_page`. Matching API and Vault releases are required. Eximbay stays off for every company Agentcard has not turned it on for.
|
|
16
|
+
|
|
17
|
+
- Pause the card token request Clover's card form sends, for the cardholder's device. Clover's iframe, on a merchant's own page or in the Clover Payments plugin for WooCommerce, sends the card to `https://token.clover.com/v1/tokens` (`token-sandbox.dev.clover.com` in Clover's sandbox) with the number encrypted under Clover's key. The sync now also asks for `capabilities=clover_card_token`, and the API serves Clover's recognizer only for a company Agentcard turned Clover on for. The SDK pauses only the card frame's own request at that exact URL. The cardholder's device builds the request again with the real card and sends it to Clover itself, and the frame gets Clover's token. Clover's request names no price, so pass `amount` and `currency`, above zero: without them `authorize()` throws `AmountRequiredError` before anything is created. Matching API and Vault releases are required. Clover stays off for every company Agentcard has not turned it on for.
|
|
18
|
+
|
|
19
|
+
## 0.23.21
|
|
20
|
+
|
|
21
|
+
- Pause ComGate's payment gateway, where most Czech and Slovak e-shops send the buyer, for the cardholder's device. The sync now also asks for `capabilities=comgate_hosted_payment_page`, and the API serves ComGate's recognizer only for a company Agentcard turned ComGate on for. The merchant's server creates the payment at ComGate and sends the buyer to `https://payN.comgate.cz/init?id=<transaction id>`. The SDK pauses that link, in the page, in a frame of it or in a window it opened, as a `hosted_form` authorization that carries the link alone, and answers the paused navigation with the `submitted_on_device` page once the cardholder's device has paid it. The link names no amount, so `authorize()` refuses one without `amount` and `currency`, above zero, with `AmountRequiredError`. Every request but a GET that your browser makes to ComGate's API (`payments.comgate.cz`, `payments-gcp.comgate.cz`) or its card frame hosts (`sec.comgate.cz`, `sec-gcp.comgate.cz`) carries the card your agent typed, part of it or its ciphertext, and the SDK fails each one and reads `unsupported` with reason `processor_card_page`. Your events and error messages name the link without its id. Matching API and Vault releases are required. ComGate stays off for every company Agentcard has not turned it on for.
|
|
22
|
+
|
|
23
|
+
- Pause card requests in a window the merchant's page opens. `attachToCdp` now attaches each window the attached page opens (`window.open`, or a form or link aimed at a new window) in the page's own browser context, and each window such a window opens, and arms it as it arms the page, so a request there reaches the same pause and the same gates. A hosted payment page the merchant opens in its own window, on the merchant's page first and then sent on to the processor, pauses there, and the window gets the `submitted_on_device` page. Earlier releases never saw a request made in such a window. The attach starts when Chromium reports the window, so a window opened straight onto a processor's page can still load it before it is armed. A window another page opens, or one in another browser context, is left alone. `attachToPlaywright` routes the page's own requests, as before.
|
|
24
|
+
|
|
25
|
+
- Name the checkout page when the request `attachToCdp` pauses is the page's own navigation away from it. A hosted payment page entry that the merchant's page sends its window to, by script, by a form or through the merchant's redirect, pauses the page's top-level navigation, and Chromium does not answer a read of that page's frame tree while it is paused. Earlier releases waited one second for that read and then created the authorization with no `checkout_origin`, so a processor whose rules hold the payment to a reviewed merchant's page refused it. The adapter now keeps the URL the page last committed, from its target when it attaches and from each document the page commits after, and names its origin at once. A request from a frame, a worker or another document is read as before.
|
|
26
|
+
|
|
27
|
+
- Pay a MakeCommerce card payment through the checkout relay, for a company Agentcard turns MakeCommerce on for (dark launch). MakeCommerce (Maksekeskus, in Estonia, Latvia, Lithuania and Finland) takes the card in its own card frame, which posts it to `https://cc.maksekeskus.ee/card-payment` under the shop's publishable key. This build declares `makecommerce_card_frame` on every sync, and the API serves the MakeCommerce entry only to a company Agentcard turned MakeCommerce on for, so every other company's MakeCommerce payments go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the frame's own one-time card payment; a post with "Remember my card" or the subscription box ticked is refused before anything is sent. The post names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total the shop's order page shows, in euros, the one currency MakeCommerce charges. The cardholder's device sends the card through the checkout relay, and the frame gets MakeCommerce's answer, the URL of its 3-D Secure page, which the frame opens in the agent's browser, where a challenge needs a person at that browser. A MakeCommerce payment also needs the matching API, Vault and checkout relay releases.
|
|
28
|
+
|
|
29
|
+
- Pay a JetBlue booking's card form, TokenEx's hosted iframe v3, for a company Agentcard turns the TokenEx iframe on for (dark launch). JetBlue takes the card number and CVV in TokenEx's cross-origin card-number frame on `htp.tokenex.com` (`test-htp.tokenex.com` in test); the cardholder name and the expiry stay on JetBlue's page. The frame posts the whole card as JSON to its own URL, query included. This build declares `tokenex_iframe_tokenize` on every sync, and the API serves the TokenEx entry only to a company Agentcard turned it on for, so every other company's TokenEx requests go through untouched. For an enabled company both adapters pause only that frame's own card post (on CDP, on the out-of-process frame's own session) and refuse every other post on the frame's path that carries a card, a stored token's CVV re-entry or a query this build has not read among them, with a `blocked` event, detail `invalid_tokenex_iframe_request`, before anything is created and without holding the page. The post names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total JetBlue's page shows. Once the cardholder approves, the frame gets TokenEx's token as the API recorded it, rebuilt from payment-core's allow-list under a JSON content type, and adds its own `cardType`; an approval whose recorded answer is not a token ends `PaymentOutcomeUnknownError`, reason `tokenex_iframe_token_unconfirmed`, and the frame gets nothing. The frame answers a repeat with nothing changed from its own cache; when it sends the same bytes again (its five-minute timer, a reset, a reload at the same URL), the SDK answers that post with the same token, a `repeat_answered` event and no second prompt, while that approval is the checkout's current one, for at most the iframe key's lifetime, and once the token reached the page only while `resolveMerchantResult` reports the order `pending`. Another placeholder or CVV, a re-created frame or a new key asks the cardholder again. `placeholderCard({ user, psp: 'tokenex_iframe' })` gives a Visa, Mastercard or American Express number the frame reads as the stored card's own brand, and refuses every other network (`brand_unsupported`), since the cardholder's device refuses a placeholder of another brand. Autopilot never pays it. Today the API refuses every TokenEx create as `unsupported_checkout` (`tokenex_iframe_account_unreviewed`) until Agentcard lists JetBlue's account, and a TokenEx payment also needs the matching API, Vault and checkout relay releases.
|
|
30
|
+
|
|
31
|
+
- Pause Przelewy24's pay wall (where most Polish shops send a buyer who pays by card) for the cardholder's device. The sync now also asks for `capabilities=przelewy24_hosted_payment_page`, and the API serves Przelewy24's recognizer only for a company Agentcard turned Przelewy24 on for. The SDK pauses the pay wall link, `https://secure.przelewy24.pl/trnRequest/<token>` (or `sandbox.przelewy24.pl` for a test payment), which carries no card, as a `hosted_form` authorization, and answers the paused navigation with the `submitted_on_device` page once the cardholder's device has paid it. The link names no amount, so send the amount Przelewy24's pay wall shows, with its currency: the API refuses a create without one (`amount_required`). The merchant's page sends the buyer there by a script, by its server's redirect or in a window it opens. `attachToCdp` pauses all three; `attachToPlaywright` pauses only the script's navigation in the page, because Playwright continues a redirect itself and does not route a window the page opens, so attach to a Przelewy24 checkout with `attachToCdp`. Every post a page the SDK watches makes to the pay wall, such as its card method's post and its card form's post, and the request to its Saferpay resolver, which names the typed card's type, leads to a card: the SDK fails each one and reads `unsupported` with reason `processor_card_page`. The SDK watches the attached page and its frames, and under `attachToCdp` each window the page opens. A window `attachToPlaywright` does not watch reaches the pay wall untouched, with the placeholder card your agent types. Matching API and Vault releases are required. Przelewy24 stays off for every company Agentcard has not turned it on for.
|
|
32
|
+
|
|
33
|
+
- Pay a Weeztix ticket shop's card form, which sends the card to Pay. (pay.nl), for a company Agentcard turned Pay. on for (dark launch): the SDK declares `pay_nl_card_token`, pauses the form's card token request and hands the form Pay.'s token answer. Pay.'s request names no price, so pass `amount` and `currency`, above zero: that is the price the cardholder approves. Without them, `authorize()` throws before anything is created:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
AmountRequiredError: A Pay. payment request names no amount, so pass amount and currency: that is the amount the cardholder approves. Nothing was created and nothing was charged.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- Pay a PayPal Card Fields checkout, such as a WooCommerce PayPal Payments store's "Debit & Credit Cards" option, for a company Agentcard turned PayPal Card Fields on for (dark launch). The store's card fields are PayPal's frames, which post the card to `https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source` (Card Fields v5) or the same path on `api-m.paypal.com` (v6). The sync now also asks for `capabilities=paypal_card_fields`, and the API serves PayPal's recognizer only to an enabled company. There both adapters pause the frames' own confirm, `authorize()` creates the authorization with it, the cardholder's device sends the card (a v5 confirm through the checkout relay, a v6 one directly), and the frame receives the order's id and status, after which the store's server captures the payment. The confirm names no amount, so pass `amount` and `currency` above zero: `authorize()` refuses one without them with `AmountRequiredError`. A confirm that asks PayPal to keep the card or asks for 3-D Secure on every payment fails in the browser with a `blocked` event. The SDK arms only the confirm's path on PayPal's hosts, never the rest of `www.paypal.com`. Every other company keeps the refusal described below, `unsupported_paypal_card_fields`. A payment also needs the matching API, relay and Vault releases.
|
|
40
|
+
|
|
41
|
+
- Name PayPal Card Fields as PayPal in a preflight inspection. PayPal's JS SDK draws each card field as a frame on `www.paypal.com`, at `/smart/card-field` for Card Fields v5 and at `/web-sdk/v6/card-fields-content` for v6, and an inspection that saw only those frames named no processor (`psp_not_detected`). Both frames now name `paypal`, and the result stays `unknown` while PayPal Card Fields ships dark. The catalog's `catalog_sha256` changes; `catalog_version` stays `2026-09-15.1`.
|
|
42
|
+
|
|
43
|
+
- Pay GoPay's card form through the checkout relay, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once a reviewed change binds GoPay's payee and amount to the approval. A Czech or Slovak shop opens GoPay's gateway as a page or as an overlay frame on its own page, and the gateway's card frame posts the card as JSON to its own URL, `https://secure.gopay.com/gp-card-comm/h/<token>` (`secure.sandbox.gopay.com` in test). This build declares `gopay_card_form` on every sync, and the API serves the GoPay entry only to a company Agentcard turned GoPay on for, so every other company's GoPay payments go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the card frame's own card post. One card frame serves every GoPay shop and its post names none, so the API takes a live post only on the checkout page of a shop Agentcard reviewed (Caramilla.cz today), refuses any other with `unsupported_checkout`, and names the reviewed shop, whatever `merchant` you send. A shop that sends the buyer away to GoPay's gateway leaves the gateway as the checkout page, which names no shop, so it is refused the same way. The post names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total GoPay's gateway shows. The cardholder's device sends the card through the checkout relay, and the frame gets GoPay's answer, an empty JSON object. GoPay's gateway then reads how the payment ended from GoPay and runs 3-D Secure in the agent's browser when the bank asks for it, where a challenge needs a person at that browser. A GoPay shop takes a card issued outside Europe only when it asked GoPay for that, and GoPay refuses such a card at authorization, with nothing charged. Your events and error messages also hide a GoPay card form's token behind any path on GoPay's card frame hosts, not only after `/h/`, and with any of its digits percent-escaped. A GoPay payment also needs the matching API, Vault and checkout relay releases.
|
|
44
|
+
|
|
45
|
+
- Keep a processor's path credential out of hold mode. `onHeld`, `controller.hold.held`, the `card_request_held`, `card_request_refused`, `card_request_expired` and `card_request_lost` events, and the `card_request_unwatched` event a shared worker's card request raises named the request's origin and path as written, so a credential a processor writes into the path, such as a GoPay card form's token or a PayMongo session, showed there. They now name it as `redactUrl` does, as every other event already did. No API or Vault release is needed.
|
|
46
|
+
|
|
47
|
+
- Pay a Revolut Business card field, from Agentcard's own company only for now (dark launch): Agentcard turns it on for another company once the API reads the order a payment names and holds its merchant, amount and currency to what the cardholder approves. Revolut's card field and card popup, on a merchant's own page (Revolut's WooCommerce plugin among them) or on Revolut's hosted checkout, post the card from their frame on `merchant.revolut.com` to `https://merchant.revolut.com/api/public/orders/<order token>/payments` as one JSON body. This build declares `revolut_card_field` on every sync, and the API serves the Revolut entry only to a company Agentcard turned Revolut on for, so every other company's Revolut payments go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the frame's card payment: a payment by Apple Pay, Google Pay or Revolut Pay on the same URL, and the frame's poll of the payment, continue untouched, and a card payment that asks Revolut to keep the card on file, or any other card body that is not the frame's own, fails in the browser before anything is created. The card payment names the order's amount in minor units but not its currency, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the order's total and its currency. The API refuses an amount that is not the card payment's, or a currency Revolut and Agentcard do not both count in hundredths (`amount_mismatch`), and any request that is not the card field's own (`invalid_revolut_request`). The cardholder's device sends the card to Revolut itself, since Revolut's host answers the Vault's origin, and the frame gets Revolut's own answer: the payment Revolut created, which the frame then follows through any 3-D Secure step in the agent's browser, where a challenge needs a person at that browser. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
|
|
48
|
+
|
|
49
|
+
- Pay SumUp's Payment Widget for a company Agentcard turns SumUp on for (dark launch). SumUp's WooCommerce plugin, payment links, Online Store and invoices all mount one widget, whose hidden form frame on `gateway.sumup.com` sends the card in one `PUT` to `https://api.sumup.com/v0.2/checkouts/<checkout id>`. This build declares `sumup_checkout_process` on every sync, and the API serves the SumUp entry only to a company Agentcard turned SumUp on for, so every other company's SumUp payments go through untouched. For an enabled company the SDK pauses that `PUT` and only that method, through `attachToCdp` or `attachToPlaywright`: the form frame is on another origin than the page, so an attachment inside the page never sees it. For that company every other body in that `PUT` fails in the frame before the SDK creates anything: a method other than a card, a card body that saves the card or splits it into installments, and the card body of SumUp's own Hosted Checkout page (`checkout.sumup.com`), which also names the product and the page's session. The request names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total SumUp's payment page shows. The API reads the checkout from SumUp, refuses a total that is not the checkout's exactly (`amount_mismatch`), a test-mode create (`live_host_on_sandbox_row`), a checkout that is paid, failed, expired, sets up recurring payments or belongs to a SumUp test merchant (`sumup_checkout_unpayable`), and a merchant Agentcard has not reviewed (`unsupported_checkout`), and it names the reviewed merchant, whatever `merchant` you send. The cardholder's device sends the card to SumUp itself, and the frame gets SumUp's own answer: the paid checkout, or the 3-D Secure step the widget then runs in the agent's browser, where a challenge needs a person at that browser. A SumUp payment also needs the matching API and Vault releases.
|
|
50
|
+
|
|
51
|
+
- Pay a GoDaddy Payments checkout, a GoDaddy Online Store's card step, for a company Agentcard turned GoDaddy Payments on for (dark launch). The store's card form is Poynt's frame on `cdn.poynt.net`, which posts the card to `https://services.poynt.net/v1/commerce/stores/<store id>/payment-tokens/generate-nonce`. The sync now also asks for `capabilities=poynt_collect_nonce`, and the API serves Poynt's recognizer only to an enabled company. There both adapters pause that post, `authorize()` creates the authorization with it, the cardholder's device sends the card through the checkout relay, and the frame receives the nonce Poynt minted, which the store's page sends to its own server to charge. The request names no amount, so pass `amount` and `currency` above zero: `authorize()` refuses one without them with `AmountRequiredError`. A live payment needs a store Agentcard reviewed at its own checkout page, or the create answers `unsupported_checkout`, and a test key is refused, since Poynt has no test host. A form that asks Poynt to keep the card fails in the browser with a `blocked` event. The store's pay button runs an invisible reCAPTCHA, so a person presses it. Every other company keeps today's path, where the request continues to Poynt untouched. A payment also needs the matching API, relay and Vault releases.
|
|
52
|
+
|
|
53
|
+
- Pause Transbank's Webpay Plus, the card payment form most Chilean shops send the buyer to, for the cardholder's device. The sync now also asks for `capabilities=transbank_webpay_hosted_payment_page`, and the API serves Webpay's recognizer only for a company Agentcard turned Webpay on for. The merchant's server creates the transaction at Transbank and sends the buyer to `https://webpay3g.transbank.cl/webpayserver/initTransaction?token_ws=<token>` with a GET, as the official WooCommerce plugin does. The SDK pauses that entry in the page or a frame of it, and with `attachToCdp` also in a window the page opened, as a `hosted_form` authorization that carries the entry alone, and answers the paused navigation with the `submitted_on_device` page once the cardholder's device has paid it. With `attachToPlaywright`, a popup that opens Webpay needs its own attachment, and the entry pauses only when the page navigates to it directly or by script. A merchant whose server redirects the checkout to Webpay needs `attachToCdp`, because Playwright's `page.route` never sees a redirect hop; with `attachToPlaywright` that checkout reads `unsupported` with reason `processor_card_page` at Webpay's token submit, and nothing is paid. The entry names no amount, so `authorize()` refuses one without `amount` and `currency`, above zero, with `AmountRequiredError`; the API takes only Chilean pesos (`clp`). Every request but a GET that your browser makes to Webpay's hosts (`webpay3g.transbank.cl`, `webpay3gint.transbank.cl`) either spends the token (`init_transaction.cgi`) or carries the card your agent typed (Webpay's card lookup, card check and card post), and the SDK fails each one and reads `unsupported` with reason `processor_card_page`. Your events and error messages name the entry without its token. Matching API, relay and Vault releases are required. Webpay stays off for every company Agentcard has not turned it on for.
|
|
54
|
+
|
|
55
|
+
## 0.23.1 to 0.23.20
|
|
56
|
+
|
|
5
57
|
- Continue a browser checkout from typed fields. `buy.ask` and `buy.confirm` now return `checkout_handoff`, the step your own agent takes when the purchase agent hands it a matched offer's checkout: the `buy_url` to open in the browser that checks out, the store and product, the listed price, the checkout authorization to create and the time to create it by. It is null on every other turn, and on a kind of step this version does not know. `buy.conversation` now returns `open_offers`, each offer handed to your agent and how far it got, and `browser_checkouts`, each checkout Agentcard ran in its own browser with its status, total, cart hash, approval link and order id. Before, the SDK dropped all three, so a caller read the step from `reply` and could not recover a browser checkout's approval link or order id from the conversation. Both lists are empty when the API sends none. TypeScript: `BuyTurn` gains `checkout_handoff` and `BuyConversation` gains `open_offers` and `browser_checkouts`; the new types `BuyCheckoutHandoff`, `BuyOpenOffer`, `BuyBrowserCheckout` and `BuyApiAmount` are exported. The listed price and the authorization hint arrive as the API writes them (`BuyApiAmount`: their `currency` typed, their amount fields passed through). An API that sends none of them reads as null and empty lists, so this release works before and after the API release that adds the browser path.
|
|
6
58
|
|
|
7
59
|
- Hold a card request with nothing created until the person confirms the total. `attachToCdp(…, { hold: true })` holds the first card request; `controller.release({ amount, currency, pageTotal })` creates the authorization at that total only when the page still shows it (`upTo: true` for a ceiling), and `controller.hold.cancel()` fails it. A held request is cancelled before its processor's own wait, and every other card request fails at once. Hold mode also holds Bolt's tokenizer (cancel only) and, with `placeholderNumbers`, any request carrying the placeholder card. New `serviceWorkers: 'bypass'` sends every armed frame's requests past site service workers instead of refusing the page, and `sharedWorkers: 'accept'` accepts a shared worker unwatched instead of refusing the page (both the default in hold mode; `'observe'` attaches and watches it where the browser allows). Exported: `CardRequestHold`, `HeldCardRequest`, `HoldOptions`, `HoldReleaseInput`, `HoldReleaseOutcome`, `HoldState`, `HoldEndedError`, `HoldAnsweredError`, `BOLT_HOLD_RULE`, `placeholderHoldRule`, `matchHoldOnlyRule`, `HOLD_DEADLINES_MS`.
|
|
@@ -36,6 +88,7 @@
|
|
|
36
88
|
|
|
37
89
|
- Pay a Paddle checkout whose card method names TokenEx, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it has confirmed that a card encrypted for one Paddle checkout cannot pay another. On such a checkout, Paddle's frame RSA-encrypts the card number and the CVV in the page itself, each on its own, under the account's TokenEx key, and posts them to `https://checkout-service.paddle.com/<checkout>/pay` (`https://sandbox-checkout-service.paddle.com/<checkout>/pay` in test) with the placeholder's first six and last four digits, expiry and brand. The SDK now pauses that `/pay`, and once the cardholder approves, the cardholder's device encrypts the real card under the key the SDK pins for that checkout's environment and the SDK writes the two ciphertexts and those five facts over the placeholder's, changing nothing else in the request. The full card number never reaches the agent's page. The sync now also asks for `capabilities=paddle_tokenex_pay`. The ciphertext goes only into the `/pay` the approval was created from, byte for byte, because the account's TokenEx key would decrypt it in any later `/pay` of that seller. A `/pay` that names no TokenEx card (PayPal, a wallet, a saved card) carries none of the cardholder's cards and continues untouched, and the SDK refuses a `/pay` that is not the frame's shape with `paddle_tokenex_pay_unsupported` before anything is sent. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
|
|
38
90
|
- Pay a Lyra payment form (PayZen, Systempay or Sogecommerce) for a company Agentcard turned Lyra on for (dark launch): the SDK declares `lyra_krypton_payment`, pauses the form's card payment and hands the form Lyra's answer with the payment id its 3-D Secure step needs.
|
|
91
|
+
|
|
39
92
|
- Keep a Lyra payment's session id out of your events and error messages. Lyra's Krypton payment form (PayZen, Systempay, Sogecommerce, Lyra Collect) sends its payment to `/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid=<id>` on the brand's API host, and that id, with the form token the page holds, continues the payment on Lyra's side. `redactUrl`, every event and every error message show it as `{session}`, as in `https://api.systempay.fr/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid={session}`. Lyra stays dark for every company Agentcard has not turned it on for, and no API or Vault release is needed.
|
|
40
93
|
|
|
41
94
|
- Stop PayPal's Card Fields and PayPal's guest card form from sending the card your agent typed to PayPal. A checkout that loads PayPal's JS SDK with `components=card-fields`, such as a WooCommerce PayPal Payments store's "Debit & Credit Cards" option, takes the card in frames on `www.paypal.com/smart/card-field` and sends it to `https://www.paypal.com/v2/checkout/orders/{id}/confirm-payment-source`; PayPal's v6 SDK sends the same request to `api-m.paypal.com`, and PayPal's sandbox uses `www.sandbox.paypal.com` and `api-m.sandbox.paypal.com`. PayPal's black "Debit or Credit Card" button takes the card on PayPal's own guest form, which sends it to `https://www.paypal.com/graphql?OnboardGuestMutation`, and Card Fields saves a card with no purchase through `graphql?UpdateVaultSetupToken`. No Agentcard payment took any of these over, and earlier releases let them through, so PayPal received the dummy card and declined it. Both adapters now fail each of them in the browser for every company, and the controller reads `unsupported` with reason `unsupported_paypal_card_fields`, or `unsupported_paypal_guest_checkout` for the guest form, and holds: to pay another way on the same page, attach again. A request with no card in it, such as a PayPal wallet confirm or the buttons' other GraphQL calls, continues untouched. A confirm whose body the SDK cannot read is failed with a `blocked` event, `unreadable_paypal_request`, and the checkout is not held; a GraphQL post it cannot read is failed the same way only when its URL names one of the two card operations. A guest form that PayPal opens in a popup window runs in another page, which the SDK covers only when you attach it to that page as well. Events and error messages now name a PayPal order as `{order}`, as in `https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source`, on every PayPal host, legacy Hosted Fields' `cors.api.paypal.com` included: an order id opens PayPal's own checkout page for that order to anyone who holds it. TypeScript: the controller's `unsupported()` reasons gain `unsupported_paypal_card_fields` and `unsupported_paypal_guest_checkout`; code that switches exhaustively over them needs the new cases.
|
|
@@ -169,7 +222,7 @@
|
|
|
169
222
|
|
|
170
223
|
- Pay a HiPay checkout whose card goes to HiPay's own vault, for a company Agentcard turned HiPay on for (dark launch). HiPay's hosted fields, which HiPay's WooCommerce, PrestaShop and Magento modules use by default, send the card from a hidden frame on `libs.hipay.com` to `https://secure2-vault.hipay-tpp.com/rest/v2/token` under the merchant's public credential, and the merchant's page gives that request 20 seconds after Pay, too soon for an approval after Pay. So the SDK pays a HiPay checkout only through `prepare({ psp: 'hipay', environment: 'production' })` (`'sandbox'` for HiPay's stage vault, with a test client), with `amount` and `currency` above zero, the total the cardholder approves: the request names none. On the live vault only a merchant Agentcard reviewed is paid, at its own checkout page and under its own public credential; none is reviewed yet, so a live `prepare()` fails with `unsupported_checkout`. The sync now also asks for `capabilities=hipay_vault_token`. The frame posts the card number alone while it is typed, and posts `/rest/v2/token/update` once it holds a token: the SDK fails both in the browser, and any post to the token URL that carries no security code with them, with a `blocked` event (`hipay_number_only`, `hipay_update_refused`) and spends no ready preparation, so the frame keeps the number and Pay sends one complete request. Once the cardholder approves, that request pauses, the cardholder's device sends the card to HiPay itself, and the frame receives HiPay's token: the SDK reads the approval every 500 ms for the 20 seconds the page waits. The SDK fails a paused request the device has not sent 12 seconds after the pause, of the 20 seconds the page waits, with reason `hipay_send_window_closed`. A payment also needs the matching API and Vault releases, and a company listed for HiPay.
|
|
171
224
|
|
|
172
|
-
- Keep a GoPay card form's token out of your events and error messages. GoPay's card frame sends the card to its own URL, `https://secure.gopay.com/gp-card-comm/h/<token>?lang=..&ver=..&SG=<signature>`, and that token, with the signature in the query, opens that payment's card form to anyone who holds it. `redactUrl`, every event and every error message now show it as `{token}` on GoPay's card frame hosts, as in `https://secure.gopay.com/gp-card-comm/h/{token}`, and drop the query as before.
|
|
225
|
+
- Keep a GoPay card form's token out of your events and error messages. GoPay's card frame sends the card to its own URL, `https://secure.gopay.com/gp-card-comm/h/<token>?lang=..&ver=..&SG=<signature>`, and that token, with the signature in the query, opens that payment's card form to anyone who holds it. `redactUrl`, every event and every error message now show it as `{token}` on GoPay's card frame hosts, as in `https://secure.gopay.com/gp-card-comm/h/{token}`, and drop the query as before. No API or Vault release is needed.
|
|
173
226
|
|
|
174
227
|
- Pay PayMongo's hosted checkout through the checkout relay, for a company Agentcard turns PayMongo on for (dark launch). Every PayMongo payment link, Storefront page and Checkout Session opens one page, `https://checkout.paymongo.com/<session>`, whose Pay button posts the card to that page's own URL as a Next.js Server Action. This build declares `paymongo_checkout_pay` on every sync, and the API serves the PayMongo entry only to a company Agentcard turned PayMongo on for, so every other company's PayMongo payments go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the checkout page's own card attach. The attach names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total PayMongo's checkout shows, in Philippine pesos. The API reads the checkout session from PayMongo and refuses a total that is not the session's to the centavo (`amount_mismatch`), a test-mode session on live credentials or the reverse (`paymongo_environment_mismatch`), and a session that has expired, is already being paid, takes no cards or adds PayMongo's fee on top (`paymongo_checkout_unpayable`), and it names PayMongo's merchant, whatever `merchant` you send. The cardholder's device sends the card through the checkout relay, and the page gets PayMongo's own answer: the paid payment, or the step toward PayMongo's 3-D Secure page, which the page then runs in the agent's browser, where a challenge needs a person at that browser. A PayMongo payment also needs the matching API, Vault and checkout relay releases.
|
|
175
228
|
|
|
@@ -177,7 +230,7 @@
|
|
|
177
230
|
|
|
178
231
|
- Keep a Przelewy24 transaction's token out of your events and error messages. Przelewy24's pay wall names its transaction by one token in every path (`/trnRequest/<token>`, its method links, `/card/p24form/<token>`, `/trnResult/<token>`), with no auth header, so the token is all a browser needs to open that transaction's pay wall, with its merchant, its amount and its card form. `redactUrl`, every event and every error message now show it as `{token}` on Przelewy24's hosts, on every route, as in `https://secure.przelewy24.pl/trnRequest/{token}`. The SDK does not pause a Przelewy24 payment yet. No API or Vault release is needed.
|
|
179
232
|
|
|
180
|
-
- Keep a Revolut order's token out of your events and error messages. Revolut's card field and card popup send the card to `https://merchant.revolut.com/api/public/orders/<order token>/payments` (`sandbox-merchant.revolut.com` in test) with no auth header that binds it, so the order token is the only credential that request needs: anyone who holds it can read the order, its amount and its merchant, and pay it. The frame then reads the payment at `/api/public/payments/<payment token>`, and Revolut's hosted checkout page names the order token in its own paths. `redactUrl`, every event and every error message now show each of those tokens as `{token}` on those hosts, as in `https://merchant.revolut.com/api/public/orders/{token}/payments`.
|
|
233
|
+
- Keep a Revolut order's token out of your events and error messages. Revolut's card field and card popup send the card to `https://merchant.revolut.com/api/public/orders/<order token>/payments` (`sandbox-merchant.revolut.com` in test) with no auth header that binds it, so the order token is the only credential that request needs: anyone who holds it can read the order, its amount and its merchant, and pay it. The frame then reads the payment at `/api/public/payments/<payment token>`, and Revolut's hosted checkout page names the order token in its own paths. `redactUrl`, every event and every error message now show each of those tokens as `{token}` on those hosts, as in `https://merchant.revolut.com/api/public/orders/{token}/payments`. No API or Vault release is needed.
|
|
181
234
|
|
|
182
235
|
- Keep a Paytrail payment's id and a Payment Highway card page's session out of your events and error messages. Paytrail's card method posts to `/payments/<transaction>/click-to-pay/loading-and-redirect` on `services.paytrail.com`, and that id opens Paytrail's own payment wall for the payment (`pay.paytrail.com/pay/<transaction>`), its amount, its merchant and every method's form, to anyone who holds it. Payment Highway, Paytrail's card platform, names its card page's session in the same way (`/form/<session>/pay_with_click_to_pay` on `v1.api.paymenthighway.io`). `redactUrl`, every event and every error message now show them as `{transaction}` and `{session}`, as in `https://services.paytrail.com/payments/{transaction}/click-to-pay/loading-and-redirect`. The SDK does not pause a Paytrail payment yet. No API or Vault release is needed.
|
|
183
236
|
|
package/PREFLIGHT.md
CHANGED
|
@@ -191,6 +191,8 @@ Juspay (`juspay`) is not in this table. Juspay launches dark: the direct SDK pay
|
|
|
191
191
|
|
|
192
192
|
Datatrans Secure Fields (`datatrans`, PCI Proxy) has reviewed discovery rules for its `secure-fields-2.0.0` script and its card iframe on `pay.datatrans.com` and `pay.sandbox.datatrans.com`, but it is not in this table. It launches dark: the direct SDK pays it only after `syncRegistry()` and only for an org Agentcard has enabled, so the bundled catalog leaves it out, its assets are not evidence, and a Datatrans checkout stays `unknown`, even when your SDK build can pay it. A page that loads Secure Fields beside another processor's SDK reads exactly as it did before.
|
|
193
193
|
|
|
194
|
+
The TokenEx hosted iframe v3 (`tokenex_iframe`, JetBlue's card form) has reviewed discovery rules for its `Iframe-v3` parent library and its `/iframe/v3` card iframe on `htp.tokenex.com` and `test-htp.tokenex.com`, and waits the same way: it launches dark, so its assets are not evidence and a TokenEx checkout stays `unknown`, even when your SDK build can pay it for an org Agentcard has enabled. Read the [TokenEx iframe section of the README](./README.md#pay-a-tokenex-iframe-checkout-dark-launch) for what the SDK covers.
|
|
195
|
+
|
|
194
196
|
ACI Worldwide's COPYandPAY widget (`aci`) is identified from its widget script and its card iframe on `eu-prod.oppwa.com`, `oppwa.com`, `eu-test.oppwa.com` and `test.oppwa.com`, but it is not in this table. It launches dark: the direct SDK pays it only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled, so the bundled catalog leaves it out and an ACI checkout stays `unknown`, even when your SDK build can pay it. Read the [ACI section of the README](./README.md#pay-an-aci-copyandpay-checkout) for what the SDK covers.
|
|
195
197
|
|
|
196
198
|
Primer (`primer`) is identified from its Web SDK v2 script `PrimerCoreSDK.min.js` and its `hosted-input.html` and `api-controller.html` card frames on `sdk.primer.io`, but it is not in this table. It launches dark: the direct SDK pays it only after `syncRegistry()` and only for an org Agentcard has enabled, so the bundled catalog leaves it out and a Primer checkout stays `unknown`, even when your SDK build can pay it. Primer Checkout (`@primer-io/primer-js`), whose hosted api-controller lives under `/web/hosted-pages/`, names its processor and returns `unknown` with `processor_variant_unverified`. Read the [Primer section of the README](./README.md#pay-a-primer-checkout) for what the SDK covers.
|
|
@@ -209,8 +211,12 @@ HiPay (`hipay`) has no discovery rule in this table. HiPay's JavaScript SDK (`li
|
|
|
209
211
|
|
|
210
212
|
Gravy Secure Fields (`gravy`) is identified from the loader its merchants load, `/secure-fields/latest/secure-fields.js` on `cdn.<merchant>.gr4vy.app` (or `cdn.sandbox.<merchant>.gr4vy.app`), but it is not in this table. It launches dark: the direct SDK pauses Gravy's card request, a `PUT` from Gravy's controller frame, only after `syncRegistry()` and only for an org Agentcard has enabled, so the bundled catalog leaves it out and a Gravy checkout stays `unknown`.
|
|
211
213
|
|
|
214
|
+
Toast (`toast`) has no discovery rule in this table while it launches dark: the direct SDK pauses Toast's card request only after `syncRegistry()` and only for an org Agentcard has enabled, so a Toast checkout stays `unknown` until a rule for Toast's payments frame ships with the release that serves it to every company.
|
|
215
|
+
|
|
212
216
|
Paddle (`paddle_vgs`) has no discovery rule in this table. Paddle's checkout frame on `buy.paddle.com` names the tokenizer it sends the card through only after the buyer's first step, and Paddle can name another one for each checkout, so nothing on the page before that step says which one a checkout uses, and a Paddle checkout stays `unknown`. The direct SDK pauses the card request a VGS checkout sends to `vault.paddle.com/cards` only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Paddle row of the [README](./README.md) processor table for what the SDK covers.
|
|
213
217
|
|
|
218
|
+
Paygent (`paygent`) has no discovery rule in this table yet. Every Paygent card form loads Paygent's `PaygentToken.js`, so a rule would name every Paygent checkout while no Paygent payment has gone through, and a Paygent checkout stays `unknown`. The direct SDK pauses the token request to `token.paygent.co.jp/n/token/request` only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Paygent row of the [README](./README.md) processor table for what the SDK covers.
|
|
219
|
+
|
|
214
220
|
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.
|
|
215
221
|
|
|
216
222
|
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.
|
package/README.md
CHANGED
|
@@ -261,7 +261,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
261
261
|
| 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. |
|
|
262
262
|
| 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 |
|
|
263
263
|
| PayPal Hosted Fields (the legacy card fields of PayPal's JS SDK; Planet Golf UK) | not supported: no Agentcard payment takes over the card these fields send to `cors.api.paypal.com`. The SDK fails that request for every company, so PayPal's payment confirm never receives the dummy card, and the controller reads `unsupported` with reason `unsupported_paypal_hosted_fields` and holds the attachment until you attach again; a PayPal wallet payment continues untouched |
|
|
264
|
-
| PayPal Card Fields (PayPal JS SDK `components=card-fields`, v5 and v6) and PayPal's guest card form (the "Debit or Credit Card" button) |
|
|
264
|
+
| PayPal Card Fields (PayPal JS SDK `components=card-fields`, v5 and v6) and PayPal's guest card form (the "Debit or Credit Card" button) | Card Fields: dark launch. After `vault.syncRegistry()`, and only for an org Agentcard has enabled, the SDK pauses the frames' confirm to `/v2/checkout/orders/{order}/confirm-payment-source` on `www.paypal.com` or `api-m.paypal.com`, always with the cardholder's approval, and the page gets the order's id and status; pass `amount` and `currency`, since the confirm names none. The guest card form is not supported. For every other org, and for the guest form always, the SDK fails each card request, so PayPal never receives the dummy card, and the controller reads `unsupported` with reason `unsupported_paypal_card_fields` (or `unsupported_paypal_guest_checkout` for the guest form) and holds the attachment until you attach again; a PayPal wallet payment continues untouched |
|
|
265
265
|
| CyberSource Secure Acceptance Silent Order POST (the merchant's own card form posted to CyberSource; Arrow Electronics) | dark launch: prepared checkout only, for an org Agentcard enabled. After `syncRegistry()`, for such an org, the SDK pauses the token create a merchant's form posts into a hidden iframe (`/silent/embedded/token/create` on `secureacceptance.cybersource.com`, or `testsecureacceptance.cybersource.com` in CyberSource's test environment), the cardholder's device sends the card to CyberSource, and the iframe gets CyberSource's own reply page. See [Pay a CyberSource Secure Acceptance checkout](#pay-a-cybersource-secure-acceptance-checkout-dark-launch). For every other company, and for every other card post to a `/silent/` path on those hosts or on `secureacceptance.in.cybersource.com` (India), no Agentcard payment takes the card over, and the SDK stops the post so CyberSource never receives the dummy card: a form the page submits as a page load, in the page or in a frame, ends on the page that says Agentcard stopped the payment, and a fetch or an XHR fails. The controller reads `unsupported` with reason `unsupported_cybersource_secure_acceptance` and holds the attachment until you attach again; a post with no `card_number`, such as a payment with a stored `payment_token`, continues untouched. The SDK does not stop Hosted Checkout, where your agent types the card on CyberSource's own page |
|
|
266
266
|
| EBANX (EBANX.js and EBANX's hosted payment page; Nuuvem Colombia) | supported for the token request (`POST /ws/token`): the SDK pauses it, and the cardholder's device sends the card there. EBANX's page then sends the card again. 3-D Secure's `/ws/threedsecureserver-generateToken`, `-authentications` and `-authentication-results` carry the card. The hosted page's confirm, `/ws/checkout-v2/confirm`, carries the card code. For a company Agentcard turned it on for, the approval's read names until when it covers those sends (`followUpsUntil`). While the Vault page stays open, the cardholder's device sends each covered one, bound to the approved request. The cardholder sees no second prompt. The page receives EBANX's answer. The confirm is covered only once 3-D Secure succeeded for the invoice it pays. It pays in one instalment and keeps no card for one-click payments. A card checkout that runs no 3-D Secure, picks instalments or saves the card fails in the browser. Every other such send fails in the browser too, for every company. EBANX never receives the dummy card or code. The page shows its own payment error. The controller reads `unsupported` with reason `unsupported_ebanx_card_resend` and holds the attachment until you attach again. After one such send fails or is refused, the SDK sends nothing more on that attachment. It also sends nothing once the checkout no longer names that approval: a final merchant result such as `completed` or `failed`, a new token request, or a new attempt after a merchant failure, and nothing while a reconciliation runs. While a send is out, `reconcile()` and `retryAfterMerchantFailure()` throw, and a new card request fails in the browser. A confirm with no card code, such as a PSE bank transfer, continues untouched |
|
|
267
267
|
| Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it. Sessions flow: 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 pauses only when Agentcard reviewed it as a merchant profile. Cinemark and Dick's Sporting Goods' own storefront take payments for a company Agentcard turned them on for; every other reviewed merchant is in `observe`, so its card requests are reported and aborted and nothing pays there yet (see "Adyen merchants that take the card on their own server"). Without a preparation, 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({ psp: 'adyen' })` moves the approval before Pay |
|
|
@@ -276,19 +276,23 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
276
276
|
| Juspay Express Checkout | dark launch: the new-card flow Swiggy's website sends from its own page, for an org Agentcard has enabled, after `vault.syncRegistry()`. Validated in local Chromium with no live merchant purchase yet; see [Pay a Juspay checkout](#pay-a-juspay-checkout) |
|
|
277
277
|
| Reviewed merchant card endpoints: AT&T, Italo, Universal Orlando, Target Optical, Opus Virtual Offices, Delta, Hilton, IHG, American Airlines, EconomyBookings, The Verb Hotel, RunSignUp, Mindbody, LookFantastic, Lexicon (FastSpring's popup checkout), and Hyatt, LifeMiles, Southwest Airlines and United Airlines, whose page encrypts the card under the merchant's own key, and the card forms Athens-Clarke County's MyRec page, Los Angeles and San Francisco on Conduent eTIMS, the D-EDGE card frame and NIC Common Checkout (NJMCdirect and other state agencies) submit as a page load | recognized in mode `card_endpoint`, every one in observe: the adapters pause each merchant's own card request and refuse it as `unsupported_checkout` before any authorization, so the dummy card never reaches the merchant, and a request to the same URL with no card in it continues untouched. A profile takes payments only after a reviewed partner HAR, a reviewed release of this SDK and the API, and per-org enablement |
|
|
278
278
|
| Datatrans Secure Fields (PCI Proxy; RaiseNow donations, British Airways) | dark launch: the card-number iframe's TOKENIZE card post only, after `vault.syncRegistry()`, and only for an org Agentcard has enabled (see [Pay a Datatrans Secure Fields checkout](#pay-a-datatrans-secure-fields-checkout)). The cardholder's device sends the card to Datatrans and the iframe receives the token and its `cardInfo`. The one live merchant account Agentcard has reviewed is RaiseNow's shared donation account, so a RaiseNow charity's one-time donation pays and every other live Datatrans checkout is refused as `datatrans_merchant_unregistered`. A post that asks PCI Proxy to keep the card on file, which British Airways's Nexus checkout sends for every new card, is refused before any prompt while Agentcard's card-on-file policy refuses it, so a Nexus checkout does not complete yet |
|
|
279
|
+
| TokenEx hosted iframe v3 (JetBlue's card form) | dark launch: the PCI card-number frame's own card post only, after `vault.syncRegistry()`, and only for an org Agentcard has enabled (see [Pay a TokenEx iframe checkout](#pay-a-tokenex-iframe-checkout-dark-launch)). Pass `amount` and `currency`. The cardholder's device sends the card to TokenEx and the frame receives TokenEx's token. No TokenEx account is reviewed yet, so the API refuses every create as `unsupported_checkout` until Agentcard lists JetBlue's |
|
|
279
280
|
| Authorize.Net Direct Post Method and SIM | dark launch (mode `hosted_form`, capability `authorize_net_dpm_form`): served only to an org Agentcard enabled for it. The card form posts one form navigation to `transact.dll` on `secure2`, `secure` or `test.authorize.net`; the cardholder's device submits it, and you poll the merchant's order state. Not eligible for auto-approval |
|
|
280
281
|
| Pelecard (Iframe/Redirect 2.0) | dark: paused only for an org Agentcard enables for Pelecard, in test mode and live. One-time card payments on `gateway21` and `gateway20.pelecard.biz`; pass `amount`, `currency` and the page's total as `pageAmount`. A live checkout pays only with a card the cardholder stored. See [Pay a Pelecard checkout](#pay-a-pelecard-checkout) |
|
|
281
282
|
| CreditGuard (Hyp PPS hosted payment page) | dark launch, prepared checkout only (see "Pay a CreditGuard checkout"): served to this build (`capabilities=creditguard_pps_process`) only for a company Agentcard enabled for it, and prepared or paid only for that company. The cardholder's device sends the card and the page reads CreditGuard's answer. 3-D Secure, OTP, installments, save-my-card and currency conversion are refused. No UAT or live capture yet |
|
|
282
283
|
| Primer (Web SDK v2 hosted fields; Printful, GetYourGuide) | dark launch (mode `token`): only for an org Agentcard has enabled; see [Pay a Primer checkout](#pay-a-primer-checkout) |
|
|
284
|
+
| Toast (Toast's payments frame; Toast online ordering) | dark launch, mode `cse` under a pinned key: after `vault.syncRegistry()`, and only for an org Agentcard has enabled, the frame's post to `payments.toasttab.com/v1/payment-methods` pauses when it is the guest card request, always with the cardholder's approval, never autopilot. Pass `amount` and `currency`, above zero: the request names no price, so that is the total the cardholder approves. A card the page asks Toast to keep for later payments, or one sealed under another key, is refused. Apple Pay and Google Pay requests on the same URL continue untouched. No live payment has gone through this route yet |
|
|
283
285
|
| Payrails web SDK (Blacklane, FlixBus) | dark launch (mode `device_encrypt`): only for an org Agentcard has enabled, and only the card form's single-use save and its single-use payment until card-on-file consent exists; see [Pay a Payrails checkout](#pay-a-payrails-checkout) |
|
|
284
286
|
| Elavon Converge (Hosted Payment Page) | dark: paused only for an org Agentcard enables for Converge, always with the cardholder's approval, never autopilot. One credit card sale in US dollars per payment page on `api.convergepay.com` or `www.convergepay.com` (`api.demo.convergepay.com` in Converge's demo environment); no amount needed. See [Pay an Elavon Converge payment page](#pay-an-elavon-converge-payment-page) |
|
|
285
287
|
| Moneris Hosted Tokenization (Moneris's card frame; Raisin donation pages) | dark launch: after `vault.syncRegistry()`, and only for an org Agentcard has enabled, the SDK pauses the frame's post to `/HPPtoken/request.php` on `www3.moneris.com` or `gateway.moneris.com` (`esqa.moneris.com` for a test row) when it carries the card number, expiry and CVD, always with the cardholder's approval. A live payment needs a merchant Agentcard reviewed: the profile id the frame names must be one pinned for the checkout page's origin (Jack.org's Raisin page today), or the create answers `unsupported_checkout`. A frame that leaves the expiry or CVD to the merchant's page, or a post to any other `request.php` URL, fails in the browser with a `blocked` event, `request_without_card`. The cardholder's device sends the card through the checkout relay, and the page gets Moneris's temporary token, which the merchant charges from its own server: pass `amount` and `currency`, the total the cardholder approves. Moneris Checkout (`/chkt/`, `/chktv2/`) is not supported |
|
|
288
|
+
| GoDaddy Payments (Poynt's card frame on a GoDaddy Online Store checkout) | dark launch: after `vault.syncRegistry()`, and only for an org Agentcard has enabled, the SDK pauses the frame's post to `/v1/commerce/stores/<store id>/payment-tokens/generate-nonce` on `services.poynt.net`, always with the cardholder's approval. A live payment needs a store Agentcard reviewed: the store id must be one pinned for the checkout page's origin, or the create answers `unsupported_checkout`; a test key is refused, since Poynt has no test host. A form that asks Poynt to keep the card fails in the browser with a `blocked` event. The cardholder's device sends the card through the checkout relay, and the page gets Poynt's nonce, which the store's server charges: pass `amount` and `currency`, the total the cardholder approves. The store's pay button runs an invisible reCAPTCHA, so a person presses it |
|
|
286
289
|
| WSPay Components (WSPay's build of Monri Components) | dark launch: the card frame's confirm of a new card, after `vault.syncRegistry()`, with `amount` and `currency`, and only for an org Agentcard has enabled; for any other org the SDK leaves WSPay's requests alone. The cardholder's device sends the card to WSPay and the frame receives WSPay's answer. A confirm that asks WSPay to keep the card on file, as Valamar's does on every booking, is paid only as a hotel's EUR 1.00 card guarantee with a card the cardholder stored. Validated in local Chromium against a model of the card frame; no WSPay sandbox run or live merchant purchase yet. See [Pay a WSPay Components checkout](#pay-a-wspay-components-checkout) |
|
|
287
290
|
| Shiji STS (MyCheck Wallet V3; Wyndham's booking pages) | dark launch, mode `cse` under a pinned key, and only for an org Agentcard has enabled. The card token a hotel booking mints guarantees the stay, so the cardholder approves with a card they stored, under a line that says the hotel can keep it on file. See [Shiji STS](#shiji-sts-mycheck-wallet-v3) |
|
|
288
291
|
| Wix checkout (Wix Cashier's card frame; Wix Payments and classic Stripe on Wix) | dark launch: only in Agentcard's own account for now, after `vault.syncRegistry()`, and only through `prepare({ psp: 'wix_payments', environment: 'production' })` at a store Agentcard reviewed, with `amount` and `currency`. The frame's post to `cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens` pauses, the cardholder's device sends the card through the checkout relay, and the frame receives Wix's token. Wix has no test environment. The SDK refuses the frame's second card request after a 401 or 403 in the browser, and fails a request still unsent 20 seconds after the pause, before the card leaves (`wix_payments_send_window_closed`) |
|
|
289
|
-
| HiPay Enterprise (HiPay's hosted fields; France, Portugal, Italy, Spain) | dark launch: after `vault.syncRegistry()`, only for an org Agentcard has enabled, and only through `prepare({ psp: 'hipay', environment: 'production' })` (`'sandbox'` for HiPay's stage vault) at a merchant Agentcard reviewed, with `amount` and `currency` above zero. The hosted fields' post to `secure2-vault.hipay-tpp.com/rest/v2/token` pauses, the cardholder's device sends the card to HiPay directly, and the frame receives HiPay's token. The frame's number-only post and its `/update` fail in the browser (`hipay_number_only`, `hipay_update_refused`), and a request still unsent 12 seconds after the pause fails before the card leaves (`hipay_send_window_closed`).
|
|
292
|
+
| HiPay Enterprise (HiPay's hosted fields; France, Portugal, Italy, Spain) | dark launch: after `vault.syncRegistry()`, only for an org Agentcard has enabled, and only through `prepare({ psp: 'hipay', environment: 'production' })` (`'sandbox'` for HiPay's stage vault) at a merchant Agentcard reviewed, with `amount` and `currency` above zero. The hosted fields' post to `secure2-vault.hipay-tpp.com/rest/v2/token` pauses, the cardholder's device sends the card to HiPay directly, and the frame receives HiPay's token. The frame's number-only post and its `/update` fail in the browser (`hipay_number_only`, `hipay_update_refused`), and a request still unsent 12 seconds after the pause fails before the card leaves (`hipay_send_window_closed`). Agentcard has reviewed one merchant so far, HappyBulle: a live checkout prepares only at `https://www.happybulle.com`, with `merchant: 'HappyBulle'`; `prepare()` at any other page fails with `unsupported_checkout`, and so does the create for a card request under any public username but HappyBulle's own |
|
|
290
293
|
| Amadeus Checkout (Air France, KLM) | dark: only for an org Agentcard enabled, and only through `prepare({ psp: 'amadeus_checkout', cardId })`. The Checkout Web SDK's card add pauses; every other action on its URL continues. Air France and KLM keep the expiry in their own form, so the agent types the stored card's real expiry there and the checkout pays only with that card. Every Data Collection Page store is refused as `amadeus_dcp_field_config_unreviewed`. No live purchase yet. See "Prepare an Amadeus Checkout card step" |
|
|
291
|
-
| Paddle checkout (Paddle's card vault;
|
|
294
|
+
| Paddle checkout (Paddle's card vault or TokenEx; any Paddle seller) | dark launch: after `vault.syncRegistry()`, and only for an org Agentcard has enabled. On a Paddle checkout whose card method names VGS, pay only through `prepare({ psp: 'paddle_vgs', environment: 'production' })` (`'sandbox'` for Paddle's sandbox) on an attachment whose `cardId` names the paying card; without one, `prepare()` fails with `card_required`. The frame's post to `vault.paddle.com/cards` pauses, the cardholder's device sends the card itself, and the frame receives the stored card's id; its second request after its 10-second timeout gets the same answer. Type `placeholderCard()`'s facts for that card into Paddle's form, and pass `amount` and `currency`, the total the cardholder approves. Only Visa, Mastercard and American Express cards are paid (`paddle_vgs_card_unsupported` otherwise), and a typed expiry or placeholder that is not the card's fails the create with `paddle_vgs_card_mismatch`. On the live vault, Agentcard pays a checkout at any Paddle seller's own https page; from any other page, such as `http://localhost:4000`, `prepare()` fails with `unsupported_checkout`. Paddle's vault keeps the card, so Paddle can charge it again without another approval, at a subscription's renewal for example. Paddle's `/pay` that follows names the approved card's first six and last four digits, expiry and brand: the SDK writes them over the ones Paddle's form read from the placeholder, and aborts a `/pay` that names another stored card or comes more than a minute later. On a Paddle checkout whose card method names TokenEx, call no `prepare()`: the SDK pauses Paddle's `/pay`, and once the cardholder approves it, writes the card the cardholder's device encrypted over the placeholder's. With a `paddle_vgs` preparation on the attachment, the SDK refuses that `/pay` with `checkout_changed`. A Paddle checkout that sends the card through Spreedly is not supported |
|
|
295
|
+
| Paygent (`PaygentToken.js`; Fundex donation forms) | dark launch: only for an org Agentcard enabled, after `vault.syncRegistry()`, and only through `prepare({ psp: 'paygent', environment: 'production' })` (`'sandbox'` for Paygent's test host) before the press that sends the card: the script gives up on its token request 35 seconds after sending it. The request to `token.paygent.co.jp/n/token/request` pauses, the cardholder's device sends the card itself, and the page receives Paygent's single-use token. One approval sends one card request, so the SDK refuses a second press, and a request for a stored card's security code too. Pass `amount` and `currency`, the total the cardholder approves. On the live host the API accepts only a reviewed merchant at its reviewed page, under its reviewed name, merchant id and token key, and in its currency (Tokyo Chinese School at `https://fundexapp.jp`, in yen), and refuses any other before anyone is asked. The merchant runs 3-D Secure after the token in the agent's browser. No live payment has gone through this route yet |
|
|
292
296
|
|
|
293
297
|
The recognizer list, and the status of each reviewed Adyen merchant profile on
|
|
294
298
|
your client, are fetched from the API at runtime (`agentcard.checkout.syncRegistry()`),
|
|
@@ -296,13 +300,14 @@ so new processors work without you shipping a release. `attachToCdp` derives the
|
|
|
296
300
|
`Fetch.enable` url patterns from that same list rather than a constant, which is
|
|
297
301
|
why the sync call belongs before the attach. `agentcard.checkout.cardUrlPatterns()` returns
|
|
298
302
|
those patterns if you arm a CDP connection yourself. Call
|
|
299
|
-
`GET /v2/checkout/recognizers?modes=token,cse,hosted_form,device_encrypt&capabilities=fiserv_card_capture,gmo_shared_pk,capture_context,juspay_txns.v1,datatrans_secure_fields_tokenize,authorize_net_dpm_form,pelecard_transaction,aci_split_card.v1,creditguard_pps_process,primer_payment_instruments,payrails_device_encrypt,converge_hpp_process,worldpay_eprotect_jsonp,wspay_confirm,shiji_sts_pinned_key,amadeus_checkout_actions.v1,worldline_mycheckout_form,verifone_card_capture,ekashu_hosted_payment_page,cybersource_sa_token_create,gravy_session_fields_put,moneris_hosted_tokenization,paddle_vgs_cards,paddle_tokenex_pay,redsys_hosted_payment_page,lyra_krypton_payment,payfast_card_pay,wix_payments_tokenize,paymongo_checkout_pay,quickpay_hosted_payment_page`
|
|
303
|
+
`GET /v2/checkout/recognizers?modes=token,cse,hosted_form,device_encrypt&capabilities=fiserv_card_capture,gmo_shared_pk,capture_context,juspay_txns.v1,datatrans_secure_fields_tokenize,authorize_net_dpm_form,pelecard_transaction,aci_split_card.v1,creditguard_pps_process,primer_payment_instruments,payrails_device_encrypt,converge_hpp_process,worldpay_eprotect_jsonp,wspay_confirm,shiji_sts_pinned_key,amadeus_checkout_actions.v1,worldline_mycheckout_form,verifone_card_capture,ekashu_hosted_payment_page,cybersource_sa_token_create,gravy_session_fields_put,moneris_hosted_tokenization,paddle_vgs_cards,paddle_tokenex_pay,redsys_hosted_payment_page,lyra_krypton_payment,payfast_card_pay,wix_payments_tokenize,paymongo_checkout_pay,pay_nl_card_token,hipay_vault_token,twoc2p_secure_pay,quickpay_hosted_payment_page,revolut_card_field,paypal_card_fields,gopay_card_form,comgate_hosted_payment_page,przelewy24_hosted_payment_page,makecommerce_card_frame,tokenex_iframe_tokenize,transbank_webpay_hosted_payment_page,sumup_checkout_process,clover_card_token,eximbay_hosted_payment_page`
|
|
300
304
|
for the list this build syncs. The API serves Fiserv's card capture only to a
|
|
301
305
|
build that lists `fiserv_card_capture`, and only for a company Agentcard turned
|
|
302
306
|
Fiserv on for. An older SDK never pauses a Fiserv request it could not finish,
|
|
303
307
|
and no SDK pauses one for a company Fiserv is off for. The API serves Juspay's
|
|
304
308
|
card flow the same way, behind `juspay_txns.v1`, Datatrans's Secure Fields
|
|
305
|
-
card post behind `datatrans_secure_fields_tokenize`, the
|
|
309
|
+
card post behind `datatrans_secure_fields_tokenize`, the TokenEx iframe's card
|
|
310
|
+
post behind `tokenex_iframe_tokenize`, the Authorize.Net DPM
|
|
306
311
|
or SIM form behind `authorize_net_dpm_form`, Pelecard's card submission
|
|
307
312
|
behind `pelecard_transaction`, ACI's split card behind `aci_split_card.v1`,
|
|
308
313
|
CreditGuard's hosted page submit behind `creditguard_pps_process`,
|
|
@@ -320,15 +325,82 @@ NMI never sees the card your agent typed. Redsys's hosted payment page
|
|
|
320
325
|
(`redsys_hosted_payment_page`) is served the same way: this build pauses the
|
|
321
326
|
merchant's signed entry form to `sis.redsys.es/sis/realizarPago` for the
|
|
322
327
|
cardholder's device and fails every other post your browser makes to Redsys.
|
|
328
|
+
Transbank's Webpay Plus (`transbank_webpay_hosted_payment_page`) is served the
|
|
329
|
+
same way: this build pauses the merchant's redirect to
|
|
330
|
+
`webpay3g.transbank.cl/webpayserver/initTransaction?token_ws=<token>` in the
|
|
331
|
+
page or a frame of it, and with `attachToCdp` also in a window the page opened,
|
|
332
|
+
for the cardholder's device, and fails every request but a GET your browser
|
|
333
|
+
makes to Webpay, so the token is never spent in your browser and Webpay never
|
|
334
|
+
sees the card your agent typed. `attachToPlaywright` covers the page it is
|
|
335
|
+
attached to and that page's frames, and pauses the entry when one of them
|
|
336
|
+
navigates to it directly or by script. Playwright's `page.route` never sees the
|
|
337
|
+
hop of an HTTP redirect, so a merchant whose server answers its checkout with a
|
|
338
|
+
redirect to Webpay needs `attachToCdp`: with `attachToPlaywright`, Webpay's
|
|
339
|
+
page loads unpaused and the SDK fails its token submit as
|
|
340
|
+
`processor_card_page`, so nothing is paid and no approval starts. A checkout
|
|
341
|
+
that opens Webpay in a popup needs that popup attached on its own, and a popup's
|
|
342
|
+
first navigation needs the integration
|
|
343
|
+
[Browser integration and merchant outcomes](#browser-integration-and-merchant-outcomes)
|
|
344
|
+
describes.
|
|
323
345
|
PayMongo's hosted checkout (`paymongo_checkout_pay`) is served on the same terms:
|
|
324
346
|
this build pauses the checkout page's own card attach on `checkout.paymongo.com`,
|
|
325
347
|
the cardholder's device sends it through the checkout relay, and the page gets
|
|
326
348
|
PayMongo's answer.
|
|
349
|
+
Przelewy24's pay wall (`przelewy24_hosted_payment_page`) is served the same way:
|
|
350
|
+
this build pauses the pay wall link `secure.przelewy24.pl/trnRequest/<token>`
|
|
351
|
+
for the cardholder's device and fails every post a page it watches makes to the
|
|
352
|
+
pay wall, and its Saferpay resolver. A merchant's server often sends the buyer
|
|
353
|
+
to that link with a redirect or in a new window, and only `attachToCdp` pauses
|
|
354
|
+
a redirect and watches a window the page opens.
|
|
327
355
|
QuickPay's hosted payment window (`quickpay_hosted_payment_page`) is served the
|
|
328
356
|
same way: this build pauses the merchant's signed entry form to
|
|
329
357
|
`payment.quickpay.net` for the cardholder's device and fails every other post
|
|
330
358
|
your browser makes to QuickPay, and the window's lookup of the typed card's
|
|
331
359
|
first digits.
|
|
360
|
+
Eximbay's payment window (`eximbay_hosted_payment_page`) is served the same
|
|
361
|
+
way: this build pauses the merchant's signed entry form to
|
|
362
|
+
`secureapi.eximbay.com/Gateway/BasicProcessor.krp` for the cardholder's device
|
|
363
|
+
and fails every other post your browser makes to Eximbay. A merchant that opens
|
|
364
|
+
Eximbay's window in a new window gets the pause only under `attachToCdp`, and
|
|
365
|
+
only once the SDK has armed that window: an entry posted into a window the page
|
|
366
|
+
opens in the same moment can leave first, and the SDK then fails the window's
|
|
367
|
+
next post, so the checkout reads `unsupported` with no card sent.
|
|
368
|
+
Revolut Business's card field (`revolut_card_field`) is served on the same
|
|
369
|
+
terms: this build pauses the frame's card payment on `merchant.revolut.com`,
|
|
370
|
+
the cardholder's device sends it to Revolut itself, and the frame gets
|
|
371
|
+
Revolut's answer.
|
|
372
|
+
GoPay's card form (`gopay_card_form`) is served only in Agentcard's own account
|
|
373
|
+
for now (dark launch), until a reviewed change binds GoPay's payee and amount
|
|
374
|
+
to the approval: this build pauses the card frame's own post on
|
|
375
|
+
`secure.gopay.com`, at a shop Agentcard reviewed, the cardholder's device sends
|
|
376
|
+
it through the checkout relay, and the frame gets GoPay's answer.
|
|
377
|
+
Payrexx Pay's card frame (`payrexx_card_frame`) is served only to a build that
|
|
378
|
+
lists it, for a company Agentcard turned Payrexx on for: this build pauses the
|
|
379
|
+
frame's own one-time card request on `checkout.payrexx.com`, the cardholder's
|
|
380
|
+
device sends it through the checkout relay, and the frame gets Payrexx's
|
|
381
|
+
answer. The API takes it only on a Payrexx page Agentcard reviewed, WWF Ost's
|
|
382
|
+
for now, and refuses any other with `unsupported_checkout`
|
|
383
|
+
(`payrexx_instance_unreviewed`): a donation page may offer a monthly choice
|
|
384
|
+
that no card request shows. When that answer starts 3-D Secure, the device also sends the frame's
|
|
385
|
+
two 3-D Secure posts under the same approval, and every other post of the card
|
|
386
|
+
to the frame fails in your browser.
|
|
387
|
+
ComGate's payment gateway (`comgate_hosted_payment_page`) is served only to a
|
|
388
|
+
build that lists it, for a company Agentcard turned ComGate on for: this build
|
|
389
|
+
pauses the gateway link the merchant sends the buyer to,
|
|
390
|
+
`payN.comgate.cz/init?id=<transaction id>`, in the page, in a frame of it or in
|
|
391
|
+
a window it opened, for the cardholder's device, and fails every request but a
|
|
392
|
+
GET your browser makes to ComGate's API and card frame hosts.
|
|
393
|
+
SumUp's Payment Widget (`sumup_checkout_process`) is served on the same terms:
|
|
394
|
+
this build pauses the widget's card `PUT` to `api.sumup.com/v0.2/checkouts/<id>`,
|
|
395
|
+
the API takes it only for a reviewed SumUp merchant and at the `amount` the
|
|
396
|
+
payment page shows, the cardholder's device sends it to SumUp, and the widget
|
|
397
|
+
gets SumUp's answer.
|
|
398
|
+
Clover's card form (`clover_card_token`) is served on the same terms: this
|
|
399
|
+
build pauses the card token request Clover's card frame sends to
|
|
400
|
+
`token.clover.com/v1/tokens`, the cardholder's device builds it again with the
|
|
401
|
+
real card encrypted under Clover's key and sends it to Clover itself, and the
|
|
402
|
+
frame gets Clover's token. Clover's request names no price, so pass `amount`
|
|
403
|
+
and `currency`, above zero: that is the amount the cardholder approves.
|
|
332
404
|
CyberSource Secure Acceptance's token
|
|
333
405
|
create (`cybersource_sa_token_create`) is served on the same terms too; every
|
|
334
406
|
other company keeps the stop every build applies to a card posted to Secure
|
|
@@ -795,6 +867,15 @@ is gone resolves as `PaymentOutcomeUnknownError` with reason
|
|
|
795
867
|
card-on-file policy refuses card on file,
|
|
796
868
|
`datatrans_card_on_file_refused` themselves, before any create, and those
|
|
797
869
|
two do not end interception for the page.
|
|
870
|
+
- TokenEx iframe refusals at create, all terminal for that page:
|
|
871
|
+
`CheckoutApiError` with `code` `processor_unavailable` (403, the TokenEx
|
|
872
|
+
iframe is not enabled for your org), `invalid_tokenex_iframe_request` (the
|
|
873
|
+
post is not the card-number frame's own card post), `unsupported_checkout`
|
|
874
|
+
(reason `tokenex_iframe_account_unreviewed`: the post names a TokenEx account
|
|
875
|
+
and origin Agentcard has not reviewed, which is every account today), or
|
|
876
|
+
`amount_required`. The adapters abort the posts behind
|
|
877
|
+
`invalid_tokenex_iframe_request` themselves, before any create, and that
|
|
878
|
+
does not end interception for the page.
|
|
798
879
|
- `CardEncryptedError`: this processor encrypts the card in-page and its
|
|
799
880
|
registry entry does not (yet) say the vault can produce that ciphertext;
|
|
800
881
|
route the purchase to an Agentcard-issued card instead.
|
|
@@ -1726,6 +1807,89 @@ const checkout = await attachToPlaywright(page, {
|
|
|
1726
1807
|
on their device. `pay.sandbox.datatrans.com` takes only a test-mode client
|
|
1727
1808
|
and `pay.datatrans.com` only a live one.
|
|
1728
1809
|
|
|
1810
|
+
### Pay a TokenEx iframe checkout (dark launch)
|
|
1811
|
+
|
|
1812
|
+
JetBlue's booking checkout ("Review & Pay") takes the card number and CVV in
|
|
1813
|
+
TokenEx's hosted iframe v3: cross-origin frames on `htp.tokenex.com`
|
|
1814
|
+
(`test-htp.tokenex.com` in test) that JetBlue's page never reads. The
|
|
1815
|
+
cardholder name and the expiry are JetBlue's own fields. When JetBlue asks the
|
|
1816
|
+
frame to tokenize, the card-number frame reads the CVV from its CVV frame and
|
|
1817
|
+
sends the whole card in one request: `POST` to its own document URL, query
|
|
1818
|
+
included, as JSON. The SDK pauses that request, the cardholder's device sends
|
|
1819
|
+
the real card to TokenEx, and the frame receives TokenEx's token, to which it
|
|
1820
|
+
adds its own `cardType` before JetBlue's page reads it.
|
|
1821
|
+
|
|
1822
|
+
```ts
|
|
1823
|
+
await vault.syncRegistry(); // the TokenEx recognizer is never in the built-in list
|
|
1824
|
+
const placeholder = await vault.placeholderCard({ user: 'your-user-id', psp: 'tokenex_iframe' });
|
|
1825
|
+
// Type placeholder.number and placeholder.securityCode into the TokenEx fields, and the
|
|
1826
|
+
// card's real expiry (placeholder.expiryMonth, placeholder.expiryYear) and name into JetBlue's own.
|
|
1827
|
+
const checkout = await attachToPlaywright(page, {
|
|
1828
|
+
vault, user: 'your-user-id', cardId: placeholder.cardId, merchant: 'JetBlue', amount: '452.10', currency: 'USD',
|
|
1829
|
+
resolveMerchantResult, // reads JetBlue's own order state; see "The same card, sent again" below
|
|
1830
|
+
});
|
|
1831
|
+
```
|
|
1832
|
+
|
|
1833
|
+
- **Dark launch.** `syncRegistry()` declares the `tokenex_iframe_tokenize`
|
|
1834
|
+
capability, and the API serves the TokenEx recognizer only to an org
|
|
1835
|
+
Agentcard has enabled for it. Every other org's SDK leaves TokenEx requests
|
|
1836
|
+
alone, as before.
|
|
1837
|
+
- **Not live yet.** A token minted into a TokenEx account can be read back as
|
|
1838
|
+
the card number by that account's holder, so the API takes a post only for a
|
|
1839
|
+
TokenEx account and merchant origin Agentcard reviewed, and names that
|
|
1840
|
+
account on the approval. None is reviewed yet: every create answers
|
|
1841
|
+
`unsupported_checkout` (reason `tokenex_iframe_account_unreviewed`) until
|
|
1842
|
+
Agentcard lists JetBlue's. A TokenEx payment also needs the matching API,
|
|
1843
|
+
Vault and checkout relay releases.
|
|
1844
|
+
- **Pass the amount.** The card post names no amount: JetBlue's server charges
|
|
1845
|
+
the token later. `authorize()` refuses one without `amount` above zero and
|
|
1846
|
+
`currency` (`AmountRequiredError`), before anything is created; a page total
|
|
1847
|
+
alone is not enough. Send the total JetBlue's page shows.
|
|
1848
|
+
- **What pauses.** Only the PCI card-number frame's own card post with its CVV
|
|
1849
|
+
frame, exactly as TokenEx's frame writes it. Any other post on the frame's
|
|
1850
|
+
`/iframe/v3` path that carries a card (a stored token's CVV re-entry, a frame
|
|
1851
|
+
without a CVV frame, 3-D Secure or fraud services turned on, a key or query
|
|
1852
|
+
this build has not read, a content type other than JSON) is aborted with a
|
|
1853
|
+
`blocked` event, detail `invalid_tokenex_iframe_request`. Nothing is created,
|
|
1854
|
+
nobody is prompted, the controller's state does not change, and the
|
|
1855
|
+
placeholder never reaches TokenEx. TokenEx's frame waits for that request
|
|
1856
|
+
until it is reloaded, so the page has to load the card form again. A post
|
|
1857
|
+
with nothing typed continues untouched, and so do the frame documents and
|
|
1858
|
+
TokenEx's BinLookup and Forter calls.
|
|
1859
|
+
- **What the frame receives.** TokenEx's token as the API recorded it, rebuilt
|
|
1860
|
+
from Agentcard's allow-list (`token`, `firstSix`, `lastFour`,
|
|
1861
|
+
`referenceNumber`, `tokenHMAC`, `cvvIncluded`) under a JSON content type. An
|
|
1862
|
+
approval whose recorded answer is not a token, TokenEx's own refusal
|
|
1863
|
+
included, ends `PaymentOutcomeUnknownError` with reason
|
|
1864
|
+
`tokenex_iframe_token_unconfirmed`, and the frame gets nothing: the card may
|
|
1865
|
+
already have left the cardholder's device.
|
|
1866
|
+
- **The same card, sent again.** TokenEx's frame answers a repeat with nothing
|
|
1867
|
+
changed from its own cache, with no request. It sends the same bytes again
|
|
1868
|
+
only when its five-minute timer has run, or after a reset or a reload at the
|
|
1869
|
+
same URL. Once a post was approved, the SDK answers that post from the same
|
|
1870
|
+
frame, byte for byte, with the same token: no second prompt, no second card
|
|
1871
|
+
sent. The adapters emit `repeat_answered` with the `authorizationId`; it is
|
|
1872
|
+
not a second payment and must not be counted as one. Another placeholder or
|
|
1873
|
+
CVV is a new approval, because the frame names the brand from the digits
|
|
1874
|
+
typed; so is a re-created frame or one JetBlue minted a new key for. The
|
|
1875
|
+
answer lasts while that approval is the checkout's current one, and at most
|
|
1876
|
+
the iframe key's lifetime (TokenEx's `ExpiresInSeconds`, at most 20
|
|
1877
|
+
minutes), after which TokenEx would refuse the same post. Once the token
|
|
1878
|
+
reached the page, before each re-send the SDK calls your
|
|
1879
|
+
`resolveMerchantResult` and answers only while it reports `pending`; an
|
|
1880
|
+
attachment with no `resolveMerchantResult` answers no re-send after the
|
|
1881
|
+
token reached the page, and each one asks the cardholder again.
|
|
1882
|
+
- **Type a placeholder of the card's brand.** The frame names the brand to
|
|
1883
|
+
JetBlue's page from the digits the agent types, so the cardholder's device
|
|
1884
|
+
refuses a card whose brand differs, before anything is sent. Use
|
|
1885
|
+
`placeholderCard({ user, psp: 'tokenex_iframe' })`: it gives a Visa,
|
|
1886
|
+
Mastercard or American Express number the frame reads as the stored card's
|
|
1887
|
+
own brand, and throws `PlaceholderCardError` (`brand_unsupported`) for any
|
|
1888
|
+
other network. Agentcard-issued cards are Mastercard.
|
|
1889
|
+
- Autopilot never pays a TokenEx checkout; the cardholder approves each one on
|
|
1890
|
+
their device. `test-htp.tokenex.com` takes only a test-mode client and
|
|
1891
|
+
`htp.tokenex.com` only a live one.
|
|
1892
|
+
|
|
1729
1893
|
### Pay a Pelecard checkout
|
|
1730
1894
|
|
|
1731
1895
|
Pelecard's hosted payment page (Iframe/Redirect 2.0) runs at
|
|
@@ -12,6 +12,10 @@ declare var AMADEUS_CARD_URLS: Readonly<{
|
|
|
12
12
|
dcp: readonly never[];
|
|
13
13
|
}>;
|
|
14
14
|
}>;
|
|
15
|
+
declare var AMADEUS_RELAY_HOSTS: Readonly<{
|
|
16
|
+
production: readonly string[];
|
|
17
|
+
sandbox: readonly string[];
|
|
18
|
+
}>;
|
|
15
19
|
declare var AMADEUS_MERCHANT_EXPIRY_POLICIES: readonly string[];
|
|
16
20
|
declare var AMADEUS_MERCHANT_EXPIRY_POLICY: string;
|
|
17
21
|
declare var AMADEUS_REFUSAL_REASONS: readonly string[];
|
|
@@ -34,6 +38,7 @@ declare function injectAmadeusCard(body: any, card: any, options?: {}): {
|
|
|
34
38
|
body: string;
|
|
35
39
|
where: any[];
|
|
36
40
|
};
|
|
41
|
+
declare function isAmadeusDeviceRequest(templateBody: any, deviceBody: any, environment: any): boolean;
|
|
37
42
|
declare function amadeusResponseOutcome(status: any, body: any, { url, card }?: {}): {
|
|
38
43
|
outcome: string;
|
|
39
44
|
reason: string;
|
|
@@ -54,4 +59,4 @@ declare function sanitizeAmadeusResponse(body: any, url: any, card: any): string
|
|
|
54
59
|
declare function amadeusFacts(body: any): {
|
|
55
60
|
refusalCode: any;
|
|
56
61
|
};
|
|
57
|
-
export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
|
|
62
|
+
export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, AMADEUS_RELAY_HOSTS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isAmadeusDeviceRequest, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 2f7fee05c7e7675b8929a13a4c2870f4d795c6d0b59cc616fb952c4a4d1cfe08
|
|
4
4
|
// src/amadeus-body.js
|
|
5
5
|
var AMADEUS_CARD_MOPID = /^creditcard[0-9]*$/;
|
|
6
6
|
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -43,6 +43,10 @@ var AMADEUS_CARD_URLS = Object.freeze({
|
|
|
43
43
|
dcp: Object.freeze([])
|
|
44
44
|
})
|
|
45
45
|
});
|
|
46
|
+
var AMADEUS_RELAY_HOSTS = /* @__PURE__ */ Object.freeze({
|
|
47
|
+
production: Object.freeze(["paypages.payment.amadeus.com"]),
|
|
48
|
+
sandbox: Object.freeze(["paypages.test.payment.amadeus.com"])
|
|
49
|
+
});
|
|
46
50
|
var AMADEUS_MERCHANT_EXPIRY_POLICIES = Object.freeze(["refuse", "fill"]);
|
|
47
51
|
var AMADEUS_MERCHANT_EXPIRY_POLICY = "fill";
|
|
48
52
|
var AMADEUS_REFUSAL_REASONS = Object.freeze([
|
|
@@ -356,6 +360,26 @@ function injectAmadeusCard(body, card, options = {}) {
|
|
|
356
360
|
write(holder, sound.name);
|
|
357
361
|
return { body: JSON.stringify(value), where };
|
|
358
362
|
}
|
|
363
|
+
function isAmadeusDeviceRequest(templateBody, deviceBody, environment) {
|
|
364
|
+
const page = readAmadeusBody(templateBody);
|
|
365
|
+
const device = readAmadeusBody(deviceBody);
|
|
366
|
+
if (!page || !device || !owns2(page, "PPID") || !owns2(device, "PPID") || sdkShapeRefusal(page) || sdkShapeRefusal(device))
|
|
367
|
+
return false;
|
|
368
|
+
const before = page.data.mopdata;
|
|
369
|
+
const after = device.data.mopdata;
|
|
370
|
+
const written = ["pan", "CVV", "expmonth", "expyear", ...owns2(before, "holdername") ? ["holdername"] : []];
|
|
371
|
+
if (!written.every((key) => owns2(after, key)))
|
|
372
|
+
return false;
|
|
373
|
+
const restored = readAmadeusBody(deviceBody);
|
|
374
|
+
for (const key of written)
|
|
375
|
+
restored.data.mopdata[key] = before[key];
|
|
376
|
+
if (JSON.stringify(restored) !== templateBody)
|
|
377
|
+
return false;
|
|
378
|
+
const cvcLength = after.vendor === "amex" ? 4 : 3;
|
|
379
|
+
if (amadeusVendorFor(after.pan) !== after.vendor || !digits(after.CVV, cvcLength, cvcLength) || !exact(MONTH, after.expmonth) || !exact(TWO_DIGITS, after.expyear) || owns2(after, "holdername") && after.holdername.trim() === "")
|
|
380
|
+
return false;
|
|
381
|
+
return environment === "sandbox" || after.pan !== before.pan;
|
|
382
|
+
}
|
|
359
383
|
var RESPONSE_LIMIT = 32768;
|
|
360
384
|
var DECLINE_LABELS = Object.freeze(["label_error_payment", "label_error_bin", "label_error_bin_vendor", "label_error_bin_type"]);
|
|
361
385
|
var EXPIRED_LABELS = Object.freeze(["session_timeout", "ppid_expired"]);
|
|
@@ -546,4 +570,4 @@ function amadeusFacts(body) {
|
|
|
546
570
|
const label = value ? sdkFailureLabel(value) : null;
|
|
547
571
|
return { refusalCode: DECLINE_LABELS.includes(label) ? label : null };
|
|
548
572
|
}
|
|
549
|
-
export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
|
|
573
|
+
export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, AMADEUS_RELAY_HOSTS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isAmadeusDeviceRequest, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
|