@agent-cards/sdk 0.23.13 → 0.23.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/PREFLIGHT.md +3 -1
  3. package/README.md +54 -13
  4. package/dist/adyen-merchant-hosted.generated.js +2 -2
  5. package/dist/amadeus.d.ts +5 -2
  6. package/dist/amadeus.js +17 -3
  7. package/dist/card-fields.generated.js +924 -3
  8. package/dist/cdp.js +83 -19
  9. package/dist/client.d.ts +97 -1
  10. package/dist/client.js +235 -16
  11. package/dist/creditguard.generated.d.ts +100 -2
  12. package/dist/creditguard.generated.js +333 -3
  13. package/dist/datatrans.generated.d.ts +19 -4
  14. package/dist/datatrans.generated.js +15 -3
  15. package/dist/ebanx.d.ts +107 -0
  16. package/dist/ebanx.generated.d.ts +78 -0
  17. package/dist/ebanx.generated.js +577 -0
  18. package/dist/ebanx.js +159 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/lifecycle.d.ts +32 -5
  22. package/dist/lifecycle.js +40 -5
  23. package/dist/paddle-tokenex.d.ts +56 -0
  24. package/dist/paddle-tokenex.generated.d.ts +67 -0
  25. package/dist/paddle-tokenex.generated.js +951 -0
  26. package/dist/paddle-tokenex.js +95 -0
  27. package/dist/paypal-card-forms.d.ts +73 -0
  28. package/dist/paypal-card-forms.js +126 -0
  29. package/dist/pre-claim.d.ts +39 -1
  30. package/dist/pre-claim.js +348 -18
  31. package/dist/preparation.d.ts +13 -0
  32. package/dist/preparation.js +22 -0
  33. package/dist/prepared-processor.d.ts +5 -1
  34. package/dist/prepared-processor.js +17 -2
  35. package/dist/primer.generated.js +960 -39
  36. package/dist/redsys.d.ts +42 -0
  37. package/dist/redsys.js +68 -0
  38. package/dist/stripe-checkout.generated.js +494 -9
  39. package/dist/wix-payments.generated.d.ts +42 -0
  40. package/dist/wix-payments.generated.js +241 -0
  41. package/package.json +8 -5
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Refuse a sandbox declaration whose endpoint is on agentcard.com, Agentcard's own domain, as one on agentcard.sh is already refused. A `sandboxMerchants` entry on `VaultClient` whose endpoint is agentcard.com or any host under it makes the constructor throw:
6
+
7
+ ```text
8
+ TypeError: sandboxMerchants: api.agentcard.com is Agentcard's own host, not a merchant's endpoint.
9
+ ```
10
+
11
+ Declare the endpoint on your own server's domain instead. An earlier SDK version passes such an endpoint on to the API, and the API refuses the checkout with `sandbox_declaration_invalid`, so nothing is created and nothing is charged.
12
+
13
+ - Pay Payfast's hosted payment page through the checkout relay, for a company Agentcard turns Payfast on for (dark launch). Payfast's card tab posts the card as one form XHR to `/eng/method/CreditCard/<uuid>/pay` on `payment.payfast.io` or `www.payfast.co.za` (`sandbox.payfast.co.za` for test payments), and that pay is the sale. This build declares `payfast_card_pay` on every sync, and the API serves the Payfast entry only to a company Agentcard turned Payfast on for, so every other company's Payfast pays go through untouched, as for an unsupported processor. For an enabled company the SDK pauses only the card tab's own form body. The pay names no price, so `authorize()` refuses one without `amount` above zero and `currency` (`AmountRequiredError`): send the total Payfast's page shows. The API reads the payment from Payfast and refuses a total that is not Payfast's to the cent (`amount_mismatch`) or a card tab that would keep the card (`payfast_keep_on_file_unsupported`), and names Payfast's receiver as the merchant, whatever `merchant` you send. The cardholder's device sends the card through the checkout relay, and the page gets Payfast's own answer: `[true]` once the payment is done, or the 3-D Secure step the card tab then runs in the agent's browser, where a challenge needs a person at that browser. A Payfast payment also needs the matching API, Vault and checkout relay releases.
14
+
15
+ - Pause Redsys's hosted payment page (the TPV Virtual redirect most Spanish banks give their merchants) for the cardholder's device. The sync now also asks for `capabilities=redsys_hosted_payment_page`, and the API serves Redsys's recognizer only for a company Agentcard turned Redsys on for. The SDK pauses the merchant's signed entry form to `sis.redsys.es/sis/realizarPago` (or `/sis/realizarPago/utf-8`), 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. Every other post your browser makes to Redsys, its card page's own post, its older page's 3-D Secure card lookup, InSite's card post and any post to Redsys's test platform, carries the card your agent typed or opens a page that asks for one: the SDK fails it and reads `unsupported` with reason `processor_card_page`. Your events and error messages name Redsys's session id, the `;jsessionid=` part of its paths, as `{session}`. Matching API and Vault releases are required. Redsys stays off for every company Agentcard has not turned it on for.
16
+
17
+ - 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.
18
+ - 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.
19
+ - 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.
20
+
21
+ - 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.
22
+
5
23
  - Keep a Rapyd hosted page's id and a Stripe Checkout Session's id out of your events and error messages. Rapyd's checkout page sends the card to `/v1/checkout/checkout_<id>` on `api.rapyd.net` (a card page to `/v1/hosted/collect/card/hp_card_<id>/payment_method`) with no auth header, so the page's id is the only credential that request needs: anyone who holds it can read the page and post a card to it until it expires. Stripe Checkout confirms a session at `/v1/payment_pages/<session id>/confirm` with the merchant's publishable key, which is public, so the session id is what lets anyone confirm a payment on it. Earlier releases named both ids in the `card_request_paused` event and in the errors `authorize()` throws, so they reached your `onEvent` handler and every log that recorded the event or the error. `redactUrl`, every event and every error message now show them as `{token}` and `{session}`, as in `https://api.rapyd.net/v1/checkout/{token}` and `https://api.stripe.com/v1/payment_pages/{session}/confirm`. `redactUrl` also masks an ACI checkout id in the shapes it used to keep: a host with a trailing dot, an escaped or doubled slash, and a string that is not a URL. A PaymentIntent or SetupIntent id stays, since confirming one also needs its client_secret. No API or Vault release is needed.
6
24
 
7
25
  - Pay a store on Paysafe Checkout's current build, 1.16.1. The loader Paysafe tells merchants to include, `checkout/v1/latest`, now runs version 1.16.1, and that build sends the card to `api.paysafe.com/checkout/api/v1/tokenize` (`api.test.paysafe.com` in its test environment), where 1.8.0 sent it to `hosted.paysafe.com`. Earlier releases did not recognize that request, so it was never paused and the agent's placeholder card reached Paysafe. The SDK now pauses it and keeps the three headers the build sends beside its credential: `X-Internal-Correlation-Id`, `X-App-Version` and `X-TransactionSource`. Paysafe.js latest sends the same three, and its replay keeps them too. `prepare({ psp: 'paysafe' })` binds a request only to a Checkout build Agentcard read, by the version the request names: 1.8.0 on `hosted.paysafe.com`, or 1.16.1 on `api.paysafe.com`, each with its own headers. A request from any other build stops with `checkout_changed`, and nothing is sent. An SDK that syncs its registry pauses the 1.16.1 request once the API release deploys; a prepared 1.16.1 checkout needs this release. Both need a Vault release after 0.6.2.
@@ -16,6 +34,19 @@
16
34
 
17
35
  - Keep a checkout's outcome when your code cancels the attachment after the checkout ended. `cancel()` rewrote every state: a checkout with an authorization or a card request in flight read `outcome_unknown` with reason `local_cancel`, and any other read `cancelled`, so an integration that cancels at cleanup lost a definite answer. On 2026-10-12 a Rapyd checkout the processor refused read `declined` (`processor_refused`) until the runner's cleanup cancel turned it into `outcome_unknown`; a `completed` checkout would have gone the same way. A checkout that reads `completed`, `declined`, `failed`, `timed_out`, `unsupported`, `cancelled` or `outcome_unknown` now keeps its status and reason through `cancel()` once no card request is in flight, or once the request in flight has its own outcome recorded, so an application that cancels from `onStateChange` or the `failed` event after a processor refusal reads `declined`. `cancel()` still stops polling, aborts any paused request and refuses every later card request, and reports no state change. A checkout still under way is unchanged, and so is one whose card request is still in flight with no outcome of its own, such as a request the page dropped mid-approval, since that authorization can still be approved on the cardholder's device: `outcome_unknown` with reason `local_cancel` once a card request is in flight or an authorization exists, `cancelled` before. No API or Vault release is needed.
18
36
 
37
+ - Pay a CreditGuard page whose transaction runs 3-D Secure through Cardinal or seals the card under a key, as Dan Hotels' gift voucher page does (MID 19006, read 2026-10-10), for a company Agentcard turned CreditGuard on for. Under a ready preparation for the page's own transaction, the SDK now answers the page's own calls beside its submit itself, with nothing sent: its card lookup (`/card/details`) as a foreign card, so the page turns its Israeli ID field off and never asks your agent for one, and its 3-D Secure calls (`/cc/ddc/init`, `/cg3ds/process/init`, `/cg3ds/process/outcome`) with no device check and no challenge, so the placeholder card never reaches CreditGuard and the page goes on to the submit the SDK pauses. The cardholder's device then runs CreditGuard's 3-D Secure with the real card before it sends the submit. With no preparation those calls go on to CreditGuard as before, and under any other preparation the SDK refuses them with a `blocked` event, `{ reason: 'creditguard_request_unsupported', refusal: 'preparation_mismatch' }`. The sealed submit (`jwePayload`) now pauses under a ready preparation for its own transaction, where earlier releases refused it as `jwe_unsupported`. `prepare()` tells the API it answers those calls (`three_d_secure: 'device'`), and the API admits a Cardinal 3-D Secure transaction only from a build that says so. Needs the API release first, which accepts that field; the API admits these transactions only once its switches for them are on, after the Vault release that runs 3-D Secure on the phone.
38
+
39
+ - Pay an EBANX checkout that runs 3-D Secure under the one approval the cardholder gives for its card token. Nuuvem's Colombia store pays this way on EBANX's hosted payment page (`payment.ebanx.com`). A payment also needs the matching API and Vault releases.
40
+ - What the page sends: after the cardholder's device sends the card to EBANX's token request (`POST /ws/token`), EBANX.js 1.135.0 and the hosted page send the card the page holds again. 3-D Secure posts the number, expiry and holder to `/ws/threedsecureserver-generateToken`, `-authentications` and `-authentication-results`. The last one repeats up to 48 times while a Netcetera challenge polls. The confirm posts the card code beside EBANX's token to `/ws/checkout-v2/confirm` on the invoice's host. Earlier releases let both reach EBANX with the dummy card. Both adapters now arm those requests for every company.
41
+ - What the SDK does with them: for a company Agentcard turned this on for, the approval's read names a window (`TokenReplay.followUpsUntil`). Inside it, the SDK asks the cardholder's device to send each request the approval covers. The cardholder sees no second prompt. The page receives EBANX's answer. The SDK reads each send back every half second, whatever `pollIntervalMs` says. After a 429 it waits longer each time, from one second up to 15.
42
+ - What one approval covers: a request to the approved request's host that names its dummy card, key, country and amount. The first 3-D Secure call names the invoice. Every later send names the same invoice. Sends follow EBANX.js's order, one at a time, at most 51. A confirm comes only after 3-D Secure answered `AUTHENTICATION_SUCCESSFUL` for that invoice. It pays in one instalment and keeps no card for one-click payments.
43
+ - What fails in the browser: any other such request. That includes a card confirm on a checkout that runs no 3-D Secure. The controller then reads `unsupported` with reason `unsupported_ebanx_card_resend` and holds. A checkout whose token request was approved keeps that approval's state.
44
+ - When the sends stop: after one such request 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 awaiting the cardholder, or a new attempt after a merchant failure. The page then cannot finish 3-D Secure or confirm.
45
+ - Lost answers: a confirm that may have left the device with no answer back reads `outcome_unknown` (`ebanx_confirm_unconfirmed`). So does a confirm whose request to the Agentcard API failed in any way but a refusal. The API may have stored that one for the device. While a send is out, `reconcile()` and `retryAfterMerchantFailure()` throw and both adapters fail a new card request in the browser, as they do while a card request is paused, and the SDK sends nothing while a reconciliation runs, so no other payment starts while a confirm may pay. A confirm whose answer is lost turns the checkout `outcome_unknown` unless the merchant already confirmed the payment (`completed`). A 3-D Secure call that fails after the checkout ended keeps that outcome.
46
+ - What continues untouched: a confirm with no card code, such as a PSE bank transfer or cash. 3-D Secure's `-record` call continues too.
47
+ - New: `VaultClient.sendEbanxFollowUp` and `EbanxFollowUpError`. `onEvent` reports `ebanx_follow_up_requested`, `ebanx_follow_up_answered` and `ebanx_follow_up_failed`. Each event names the authorization and the step, never the request.
48
+ - TypeScript: the controller's `unsupported()` reasons gain `unsupported_ebanx_card_resend`. Code that switches exhaustively over them needs the new case.
49
+
19
50
  - Pay IKEA US's ACI checkout as its live payment step sends it. With ACI's ReD Shield screening on, the widget posts the device fingerprint, `customer.browserFingerprint.value` alone, to the checkout's card URL on load, and 0.23.9 refused it as `aci_unsupported_request`. That refusal also failed the checkout's CVC request at once whenever it reached the SDK before the card-number request at Pay, so the widget's Pay failed. The fingerprint now continues untouched, up to the 4,096 characters ACI takes; a longer one is still refused, and a refused request that names no card number no longer fails the checkout's CVC or expiry requests, which wait for the card-number request as before. `/payment` now continues with `shopperResultTarget=_top`, the value IKEA's widget options set and ACI's own default for its final redirect, which 0.23.9 refused after the cardholder's device had already sent the card; any other target is still refused as `aci_unsupported_request`. No API or Vault release is needed.
20
51
 
21
52
  - Pay an APCOA airport drop-off entry on NMI's hosted payment page (`ekashu`). Every APCOA entry carries APCOA's own ASP.NET Core anti-forgery token, `__RequestVerificationToken`, and the API refused it as a field of NMI's card page (`hosted_form_field_refused`, reason `not_an_entry`), so an attached checkout at Heathrow's drop-off could not get past the create. The API now takes the merchant's token and still refuses an entry that carries `ekashu_stage`, `ekashu_context` or `ekashu_submission_id`. No SDK upgrade is needed: the API takes the entry once it deploys, and the cardholder's phone fills NMI's card page from the next Vault release. NMI stays off for every company Agentcard has not turned it on for.
@@ -24,6 +55,8 @@
24
55
 
25
56
  - Pause a Datatrans card post whose expiry the merchant's own form keeps. RaiseNow's donation widget (Tamaro, merchant `3000022877`) collects the expiry in its own field and sends it to RaiseNow beside the token, so its card post carries no `expm` or `expy`, and earlier releases refused it in the browser as `invalid_datatrans_request` before any create. The post now pauses like any other, and the cardholder's device writes the card number and CVV and adds no expiry, as the page sent none. Type the card's real expiry (`placeholderCard()`) into the merchant's own expiry field: the merchant charges with the expiry its form holds. A post with only one of the two, or with no expiry while it asks to keep the card on file, is still refused as `invalid_datatrans_request`. Datatrans stays dark for every company Agentcard has not enabled, no live Datatrans merchant is reviewed yet, and a payment also needs the matching API and Vault releases.
26
57
 
58
+ - Pay a RaiseNow donation through Datatrans. RaiseNow's donation widget (Tamaro) tokenizes the card into RaiseNow's shared Datatrans account, `3000022877`, for every charity it collects for, and the API refused that account at create as `datatrans_merchant_unregistered`, as it refuses every live Datatrans account Agentcard has not reviewed. RaiseNow's account is now reviewed, and it is the only live Datatrans account that is. Pass the charity's name as `merchant`, and the donation's `amount` and `currency`, since the card post names neither. The cardholder's approval shows the charity you named, said to be your agent's word, with RaiseNow as the merchant account under it: RaiseNow's account takes the card, and nothing binds the charity's name to it. Choose a one-time donation: a monthly one sends the same card post, so the approval cannot say that RaiseNow will charge the card again. Since RaiseNow can, a live donation pays only with a card the person stored in their Vault: a card your company added answers `card_not_stored` at create, at the card choice and at the pre-replay check, and no read offers it. No SDK upgrade is needed, since 0.23.10 already pauses the post: the API takes it once it deploys, and the cardholder's phone pays it from the next Vault release. British Airways's accounts are still refused, and Datatrans stays dark for every company Agentcard has not enabled.
59
+
27
60
  - Pay Air France's and KLM's Amadeus card step with the expiry your agent typed into the airline's own form. Both airlines keep the card's expiry in a field of their own and send it to their own server, so the Checkout Web SDK's add carries an empty `expmonth` and `expyear`, and 0.23.9 refused that add in the browser with `amadeus_merchant_held_expiry`, before any row or prompt. The add now binds the preparation, and the cardholder's device writes the stored card's own month and year into it beside the real card. Type `placeholderCard()`'s `expiryMonth` and `expiryYear` into the airline's expiry field, and its `number` and `securityCode` into Amadeus's card fields. `prepare({ psp: 'amadeus_checkout' })` now needs `cardId`, the card whose expiry you typed (`card_required`), and the approval is locked to that card; a ready checkout naming another card reads `ready_unconfirmed`. Amadeus stays dark: only a company Agentcard turned it on for is served it.
28
61
 
29
62
  - Read The Container Store's Place Order request (`POST https://www.containerstore.com/checkout/api/submit`, a new card alone in `paymentMethods`) as its reviewed Verifone card request. Its profile (`containerstore_checkout`) stays in `observe` with no key pinned, so for a company Agentcard turned Verifone on for, the adapters still abort that request before it leaves the browser and report `verifone_profile_observed`, now with the reason that Agentcard has not reviewed The Container Store's key. A body with a gift card, a second payment method, a saved card, `defaultWallet` set or a loyalty enrollment is refused by the request's rules, and any other blob-bearing request there aborts as before. Verifone stays off for every other company. The cardholder's device can now encrypt under a Verifone key on secp256k1, the curve The Container Store's live key is on; the SDK itself never encrypts.
@@ -100,6 +133,12 @@
100
133
 
101
134
  - Pay a Paddle checkout that sends the card to Paddle's card vault, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it has confirmed that a card stored for one Paddle seller cannot pay another. On a checkout whose card method names VGS, Paddle's checkout frame on `buy.paddle.com` posts the card to `https://vault.paddle.com/cards` (`https://sandbox-vault.paddle.com/cards` in test) and sends that request once more when it gets no answer within 10 seconds, too soon for an approval after Pay. So the card is paid only through `prepare({ psp: 'paddle_vgs', environment: 'production' })` (`'sandbox'` for Paddle's sandbox) on an attachment whose `cardId` names the card whose `placeholderCard()` facts you typed into Paddle's form; without one, `prepare()` fails with `card_required`, and the approval is locked to that card. The sync now also asks for `capabilities=paddle_vgs_cards`. Once the cardholder approves, the frame's request pauses, the cardholder's device sends the card to Paddle's vault itself, and the frame receives the stored card's id and nothing else; the frame's second request after its 10-second timeout, the same body under the same bearer, gets the same answer, and any other request is refused. Paddle's request names no amount, so the cardholder approves the `amount` and `currency` you pass. The lane pays Visa, Mastercard and American Express cards: `prepare()` fails with `paddle_vgs_card_unsupported` for a card on another network, and the create fails with `paddle_vgs_card_mismatch` when the expiry or placeholder you typed is not the card's. On Paddle's live vault, Agentcard pays only a seller it has reviewed, at the checkout page it reviewed (Rectangle Pro at `https://rectangleapp.com` today), and the approval names that seller and says it can keep the card on file, because the card stays stored in Paddle's vault. Paddle's own `/pay` call, which follows the stored card's id, names the card it pays by its first six and last four digits, expiry and brand, and Paddle's form reads those from the placeholder you typed. The SDK writes the approved card's own over them, the details the cardholder's device read from the card, and changes nothing else in that call. A `/pay` that names another stored card, comes from another frame, comes more than a minute after the id reached the frame, or follows the first one is aborted, and Paddle charges nothing. A Paddle checkout that sends the card through TokenEx or Spreedly is not paid. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
102
135
 
136
+ - Keep a Payfast payment's id out of your events and error messages. Payfast's hosted payment page sends the card to `/eng/method/CreditCard/<uuid>/pay` on its own host (`payment.payfast.io`, `www.payfast.co.za`, `sandbox.payfast.co.za`) with no auth header, so the payment's uuid is the only credential that request needs: anyone who holds it can read the payment page, its amount and its merchant. `redactUrl`, every event and every error message now show it as `{uuid}` on every host Payfast owns, on every route of the page, as in `https://payment.payfast.io/eng/method/CreditCard/{uuid}/pay`. The SDK does not pause a Payfast payment yet. No API or Vault release is needed.
137
+
138
+ - Pay a live Pelecard checkout, for a company Agentcard turned Pelecard on for. Pelecard's test and live terminals share `gateway21.pelecard.biz` and `gateway20.pelecard.biz`, and neither the payment page nor its request says which kind a page is on, so the API refused every live Pelecard create with `400 pelecard_live_unsupported`, before any row or prompt. On 2026-10-11 Agentcard accepted that a live payment page could sit on one of Pelecard's public test terminals, and a live create now parks like a test one. The cardholder approves under Pelecard's note, which says the merchant may have Pelecard keep the card, since a merchant can set `CreateToken` when it creates the payment page, and only a card the cardholder stored pays: the API refuses a card a company added as `card_not_stored`. A test-mode checkout still takes only a documented test card. No SDK upgrade is needed. A payment also needs the matching API, Vault and checkout relay releases, with `CHECKOUT_PELECARD_RELAY_ENABLED` on and the company listed for Pelecard.
139
+
140
+ - Pay a Wix checkout whose card goes to Wix's own tokenizer, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it checks that the site instance Wix's card frame sends belongs to the reviewed store. Every Wix checkout mounts Wix Cashier's card frame, and for Wix Payments and classic Stripe on Wix that frame posts the card to `https://cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens`. Wix's payment widget fails the payment 30 seconds after it asks the frame for a token, too soon for an approval after Pay, so the SDK pays a Wix checkout only through `prepare({ psp: 'wix_payments', environment: 'production' })`, at a store Agentcard reviewed (ParaHouse Magazine, Psalms & Potions and Alexandra Hagel today), with `amount` and `currency`, the total the cardholder approves: the request names none. Wix has no test environment, so a test client's `prepare()` fails with `live_host_on_sandbox_row`. The sync now also asks for `capabilities=wix_payments_tokenize`. Once the cardholder approves, the frame's request pauses, the cardholder's device sends the card through the checkout relay, and the frame receives Wix's token. The frame sends its card request once more under a fresh site instance after Wix answers 401 or 403: the SDK refuses that second request in the browser and never answers it from the first approval. The SDK fails a paused request the cardholder's device has not sent 20 seconds after the pause, of the 30 seconds Wix waits, with reason `wix_payments_send_window_closed`, as it fails a prepared Secure Acceptance token create, and the device sends nothing past its own earlier boundary.
141
+
103
142
  ## 0.23.0
104
143
 
105
144
  ### Upgrading from 0.22.0
package/PREFLIGHT.md CHANGED
@@ -203,6 +203,8 @@ WSPay Components (`wspay`) is identified from its component scripts and its card
203
203
 
204
204
  Shiji STS (`shiji_sts`), the card leg of MyCheck Wallet V3 at La Quinta by Wyndham, is identified from the in-page wallet script `wallet-sdk-v3.mycheckapp.com/{version}/static/js/main.js` (and its `-sandbox` and `-test` hosts) and from Shiji's proxy `cdn.shijipayment.com/sts/sts.proxy.v2.1.js` (and its `cdn.shijipayment.dev` copy), but it is not in this table. It launches dark: the direct SDK acts on it only after `syncRegistry()` and only for an org Agentcard has enabled, and even then it refuses every card request as card on file (`shiji_sts_keep_on_file`) until Agentcard can ask the cardholder to let a hotel keep the card, so the bundled catalog leaves it out and a Shiji checkout stays `unknown`. MyCheck's iframe wallet (`sdk.js`, `wallet-iframe.html`) and Shiji's `shijipayments.latest.min.js` name their processor and return `unknown` with `processor_variant_unverified`. Read the [Shiji STS section of the README](./README.md#shiji-sts-mycheck-wallet-v3).
205
205
 
206
+ Wix Payments (`wix_payments`) has no discovery rule in this table. Wix Cashier's card frame on `cashier-pci.wixapps.net` is the same for every provider a Wix site connects, and for Square and Wix's Stripe Gateway it sends the card to the processor's own SDK rather than to Wix's tokenizer, so the frame on a page is no evidence of this lane, and a Wix checkout stays `unknown`. The direct SDK pauses the card request the frame sends to Wix's tokenizer only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Wix row of the [README](./README.md) processor table.
207
+
206
208
  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`.
207
209
 
208
210
  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.
@@ -219,7 +221,7 @@ Adyen's `supported` covers the Sessions payment request on Adyen's own hosts. So
219
221
 
220
222
  Authorize.Net Direct Post Method and SIM ship dark. The SDK pauses their `transact.dll` card form only for an org Agentcard enabled for them (capability `authorize_net_dpm_form`), and the bundled catalog leaves them out, so the table above does not list them and inspection answers for their forms exactly as it did before: the SIM hosted form on `secure.authorize.net` identifies Authorize.Net and returns `unknown` with `processor_variant_unverified`.
221
223
 
222
- The catalog also names Pelecard, which ships dark: the API serves its recognizer only to an org Agentcard has enabled, in test mode only. Pelecard's hosted payment page and its payment scripts on `gateway21.pelecard.biz` and `gateway20.pelecard.biz` identify the processor and return `unknown`, because the bundled direct SDK profile declares no Pelecard support while it ships dark, even though an enabled org's SDK can pay the page's one-time card submission. The legacy 1.0 form on `gateway.pelecard.biz` returns `unknown` with `processor_variant_unverified`.
224
+ The catalog also names Pelecard, which ships dark: the API serves its recognizer only to an org Agentcard has enabled, in test mode and live. Pelecard's hosted payment page and its payment scripts on `gateway21.pelecard.biz` and `gateway20.pelecard.biz` identify the processor and return `unknown`, because the bundled direct SDK profile declares no Pelecard support while it ships dark, even though an enabled org's SDK can pay the page's one-time card submission. The legacy 1.0 form on `gateway.pelecard.biz` returns `unknown` with `processor_variant_unverified`.
223
225
 
224
226
  CreditGuard's hosted payment page (Hyp PPS) ships dark and is not in the table. A PPS page or its template script names `creditguard` and the result stays `unknown`; the legacy CGMPI page returns `processor_variant_unverified`. The direct SDK pays CreditGuard only under a prepared checkout, for a company Agentcard enabled for it (the README's "Pay a CreditGuard checkout"), so the bundled profile declares no CreditGuard support yet.
225
227
 
package/README.md CHANGED
@@ -255,7 +255,9 @@ Coverage is specific to the processor request format, merchant setup, browser tr
255
255
  | 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. |
256
256
  | 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 |
257
257
  | 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 |
258
+ | PayPal Card Fields (PayPal JS SDK `components=card-fields`, v5 and v6) and PayPal's guest card form (the "Debit or Credit Card" button) | not supported: no Agentcard payment takes over the card these send to `www.paypal.com` or `api-m.paypal.com`. The SDK fails each card request for every company, 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 |
258
259
  | 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 |
260
+ | 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 |
259
261
  | 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 |
260
262
  | ACI Worldwide COPYandPAY (Halfords) | dark launch: served only after `syncRegistry()` and only for an org Agentcard enabled; prepared checkout only. The card-number request is replayed from the cardholder's device, the page's own CVC and expiry requests are answered locally, and `/payment` continues once. See [Pay an ACI COPYandPAY checkout](#pay-an-aci-copyandpay-checkout) |
261
263
  | Tranzila | supported (mode `hosted_form`): the cardholder finishes on Tranzila's own page; the paused form navigation resolves to a synthetic page, and you poll the merchant's order state |
@@ -267,9 +269,9 @@ Coverage is specific to the processor request format, merchant setup, browser tr
267
269
  | CyberSource Flex Microform | dark launch: Microform 2.12.1 card fields only, after `vault.syncRegistry()`, and only for an org Agentcard has enabled. For any other org the API does not serve the recognizer, so nothing pauses there. The cardholder's device seals the card for CyberSource and the card field receives the transient token. Validated in local Chromium; no live merchant purchase yet. See [Pay a CyberSource Flex Microform checkout](#pay-a-cybersource-flex-microform-checkout) |
268
270
  | 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) |
269
271
  | 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 |
270
- | Datatrans Secure Fields (PCI Proxy; 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`. 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 |
272
+ | 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 |
271
273
  | 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 |
272
- | Pelecard (Iframe/Redirect 2.0) | dark: paused only for an org Agentcard enables for Pelecard, in test mode only. One-time card payments on `gateway21` and `gateway20.pelecard.biz`; pass `amount`, `currency` and the page's total as `pageAmount`. See [Pay a Pelecard checkout](#pay-a-pelecard-checkout) |
274
+ | 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) |
273
275
  | 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 |
274
276
  | 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) |
275
277
  | 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) |
@@ -277,6 +279,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
277
279
  | 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 |
278
280
  | 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) |
279
281
  | 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) |
282
+ | 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`) |
280
283
  | 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" |
281
284
  | Paddle checkout (Paddle's card vault; Rectangle Pro) | dark launch: only in Agentcard's own account for now, after `vault.syncRegistry()`, and 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`. On a Paddle checkout whose card method names VGS, 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 only a reviewed seller at its reviewed page is paid (Rectangle Pro at `https://rectangleapp.com`), and the approval says that seller can keep the card on file. 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. A Paddle checkout that sends the card through TokenEx or Spreedly is not supported, and no live payment has gone through this route yet |
282
285
 
@@ -286,7 +289,7 @@ so new processors work without you shipping a release. `attachToCdp` derives the
286
289
  `Fetch.enable` url patterns from that same list rather than a constant, which is
287
290
  why the sync call belongs before the attach. `agentcard.checkout.cardUrlPatterns()` returns
288
291
  those patterns if you arm a CDP connection yourself. Call
289
- `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`
292
+ `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,redsys_hosted_payment_page`
290
293
  for the list this build syncs. The API serves Fiserv's card capture only to a
291
294
  build that lists `fiserv_card_capture`, and only for a company Agentcard turned
292
295
  Fiserv on for. An older SDK never pauses a Fiserv request it could not finish,
@@ -306,7 +309,11 @@ same holds for the Verifone profiles and `verifone_card_capture`. NMI's hosted
306
309
  payment page (`ekashu_hosted_payment_page`) is served on the same terms: this
307
310
  build pauses the merchant's entry form to `live.ekashu.com` for the
308
311
  cardholder's device and fails every other post your browser makes to NMI, so
309
- NMI never sees the card your agent typed. CyberSource Secure Acceptance's token
312
+ NMI never sees the card your agent typed. Redsys's hosted payment page
313
+ (`redsys_hosted_payment_page`) is served the same way: this build pauses the
314
+ merchant's signed entry form to `sis.redsys.es/sis/realizarPago` for the
315
+ cardholder's device and fails every other post your browser makes to Redsys.
316
+ CyberSource Secure Acceptance's token
310
317
  create (`cybersource_sa_token_create`) is served on the same terms too; every
311
318
  other company keeps the stop every build applies to a card posted to Secure
312
319
  Acceptance. So is Gravy's session fields `PUT` (`gravy_session_fields_put`):
@@ -891,15 +898,24 @@ is gone resolves as `PaymentOutcomeUnknownError` with reason
891
898
  It declares **no dependencies**, so the workspace
892
899
  lockfile needs no importer entry for it (a new package with its own deps cannot
893
900
  be installed here without regenerating the lockfile, and a full regen drifts
894
- unrelated transitive versions). The voice module's streaming door is vendored
895
- from `packages/voice/src/core/stream.ts` by `scripts/generate-voice-stream.mjs`
896
- (`pnpm check:voice-stream` says when the copy has drifted). Build it with the
897
- workspace TypeScript:
901
+ unrelated transitive versions). The build writes the SDK's copies of
902
+ payment-core's rules (`src/*.generated.ts`), the voice module's streaming door
903
+ from `packages/voice/src/core/stream.ts`, and the Kernel kit's
904
+ `examples/preflight/kernel-native/inventory.json`. Git ignores those files, so
905
+ build before you test, with the workspace TypeScript:
898
906
 
899
907
  ```bash
900
908
  cd packages/checkout && pnpm build && pnpm test
901
909
  ```
902
910
 
911
+ `pnpm test` checks those files first. A missing or stale one stops the run with
912
+ the command that writes it:
913
+
914
+ ```text
915
+ Missing shared-core projection: stripe-checkout.generated.ts
916
+ Run `npm run build` in packages/checkout. It writes the SDK's src/*.generated.ts from payment-core's build.
917
+ ```
918
+
903
919
 
904
920
  ## Browser integration and merchant outcomes
905
921
 
@@ -1573,7 +1589,8 @@ const checkout = await attachToPlaywright(page, {
1573
1589
 
1574
1590
  ### Pay a Datatrans Secure Fields checkout
1575
1591
 
1576
- British Airways takes cards in Datatrans Secure Fields (PCI Proxy). The card
1592
+ RaiseNow's donation widget (Tamaro) and British Airways take cards in
1593
+ Datatrans Secure Fields (PCI Proxy). The card
1577
1594
  number and CVV are Datatrans's own iframes on `pay.datatrans.com`
1578
1595
  (`pay.sandbox.datatrans.com` in test), and the card-number iframe sends the
1579
1596
  whole card in one request: `POST /upp/payment/SecureFields/paymentField`,
@@ -1655,6 +1672,20 @@ const checkout = await attachToPlaywright(page, {
1655
1672
  - **Merchant accounts.** A token minted into a Datatrans account can be read
1656
1673
  back as the card number by that account's holder, so the API refuses a
1657
1674
  merchant account Agentcard has not reviewed (`datatrans_merchant_unregistered`).
1675
+ The one live account reviewed is RaiseNow's shared donation account
1676
+ (`3000022877`), which every RaiseNow charity's donation widget posts to.
1677
+ - **RaiseNow donations.** Pass the charity's name as `merchant`, and the
1678
+ donation's `amount` and `currency`: the card post names neither, and
1679
+ without them the create answers `amount_required`. The cardholder's
1680
+ approval shows the charity you named with RaiseNow as the merchant account
1681
+ under it, because RaiseNow's account takes the card for every charity and
1682
+ nothing binds the name you pass to it, so the approval says the name is
1683
+ your agent's. Choose a one-time donation: a monthly one sends the same
1684
+ card post, so the approval cannot say that RaiseNow will charge the card
1685
+ again. Since RaiseNow can, a live donation pays only with a card the
1686
+ person stored: a card your company added answers `card_not_stored`.
1687
+ Type the card's real expiry from `placeholderCard()` into RaiseNow's own
1688
+ expiry field.
1658
1689
  - Autopilot never pays a Datatrans checkout; the cardholder approves each one
1659
1690
  on their device. `pay.sandbox.datatrans.com` takes only a test-mode client
1660
1691
  and `pay.datatrans.com` only a live one.
@@ -1671,8 +1702,8 @@ answer, so its own script takes the buyer to the merchant's landing page.
1671
1702
 
1672
1703
  Pelecard ships dark: `syncRegistry()` asks for the `pelecard_transaction`
1673
1704
  capability, and the API serves the recognizer only to an org Agentcard has
1674
- enabled for Pelecard, in test mode only. For every other org the SDK leaves
1675
- Pelecard's requests alone.
1705
+ enabled for Pelecard. For every other org the SDK leaves Pelecard's requests
1706
+ alone.
1676
1707
 
1677
1708
  ```ts
1678
1709
  await vault.syncRegistry();
@@ -1716,6 +1747,16 @@ const checkout = await attachToPlaywright(page, {
1716
1747
  request is aborted, nothing is created, and the page's next submission is
1717
1748
  judged afresh. A merchant can still set `CreateToken` when it creates the
1718
1749
  payment page, which no request shows.
1750
+ - Pelecard's test and live terminals share `gateway21` and `gateway20`, and
1751
+ neither the payment page nor its request says which kind a page is on, so
1752
+ the API takes a test-mode create and a live one the same way. In test mode
1753
+ the cardholder's device sends only a documented test card, because anyone
1754
+ holding the demo login Pelecard publishes can read back a payment made on
1755
+ one of its public test terminals. A live checkout pays only with a card the
1756
+ cardholder stored, under an approval that says the merchant may have
1757
+ Pelecard keep the card, since a merchant can set `CreateToken` when it
1758
+ creates the payment page. The API refuses a card a company added as
1759
+ `card_not_stored`.
1719
1760
  - The page's other tabs post to the same URL with no card (Bit, wallets, the
1720
1761
  PIN pad, bank transfer) and continue untouched.
1721
1762
  - The page waits up to ten minutes for the answer, and Pelecard's payment
@@ -1733,9 +1774,9 @@ await controller.prepare({ psp: 'creditguard', environment: 'production', paymen
1733
1774
  // 'sandbox' for CreditGuard's UAT page on ppsuat.creditguard.co.il
1734
1775
  ```
1735
1776
 
1736
- Agentcard reads that transaction from CreditGuard before the cardholder is asked. Pass the `amount` and `currency` CreditGuard holds (ILS in agorot: `24000` is 240.00 ILS); another pair is refused as `amount_mismatch`. A page the Vault cannot finish (3-D Secure, OTP, currency conversion, installments, a required Israeli ID, or a form that hides a card field or asks for a field the cardholder's device does not fill) is refused as `creditguard_transaction_refused`, with CreditGuard's reason in `detail`. The merchant page must be HTTPS under a dotted hostname, because every submit names it.
1777
+ Agentcard reads that transaction from CreditGuard before it asks the cardholder. Pass the `amount` and `currency` CreditGuard holds (ILS in agorot: `24000` is 240.00 ILS); another pair gets `amount_mismatch`. A page the Vault cannot finish (OTP, currency conversion, installments, an Israeli ID demanded even for a foreign card, a form that hides a card field or asks for a field the cardholder's device does not fill, 3-D Secure through Nuvei, or 3-D Secure through Cardinal while Agentcard has not turned it on) gets `creditguard_transaction_refused`, with CreditGuard's reason in `detail`. Agentcard refuses a page that seals the card under a key (`jwePayload`) the same way, as `jwe_unsupported`, until it turns the encrypted card on. The merchant page must be HTTPS under a dotted hostname, because every submit names it.
1737
1778
 
1738
- After the approval, click the page's Pay once. Only the page's own new-card submit for that transaction pauses: the cardholder's device sends the real card to CreditGuard, and the page reads CreditGuard's answer, rebuilt from payment-core's allow-list, then moves on to the merchant's landing page. The page's card lookup, its transaction read and every other request continue untouched with your placeholder, so type a foreign test number.
1779
+ After the approval, type the card and click the page's Pay once. Under the ready preparation the SDK answers the page's own card lookup itself, as a foreign card, so the page turns its Israeli ID field off and asks your agent for none. On a 3-D Secure transaction through Cardinal it answers the page's own 3-D Secure calls too (the device check, the 3-D Secure start and its outcome), with no device check and no challenge, so your placeholder never reaches CreditGuard; the cardholder's device runs 3-D Secure with the real card, showing any challenge from the bank on the approval page, before it sends the submit. Only the page's own new-card submit for that transaction pauses, sealed or not: the cardholder's device sends the real card to CreditGuard, and the page reads CreditGuard's answer, rebuilt from payment-core's allow-list, then moves on to the merchant's landing page. The page's transaction read and every other request continue untouched.
1739
1780
 
1740
1781
  A submit the device would not fill is aborted before anything is created, with a `blocked` event `{ reason: 'creditguard_request_unsupported', refusal }`: `keep_on_file` ("save my card"), `installments`, `dcc`, `personal_id`, `saved_card`, `wallet` and the like. The preparation stays ready, so untick the option and click Pay again. Without a ready preparation the submit is refused with `PreparationRequiredError`. CreditGuard's own 3-D Secure call to Nuvei, from its page or from any frame inside it, is refused, and the attachment reads `unsupported` with reason `creditguard_three_d_secure`; it is never approved as a Nuvei payment. Autopilot never pays CreditGuard.
1741
1782
 
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 4790fdfc656acbda50ddf8471507933ddd4938f4c5b351ec096a9549a7c8c257
3
+ // artifact-sha256: e15beada28ae21bc7d0145bea84f12379a45a8815f0cbb1405a2a78b14b34e4f
4
4
  // src/deep-freeze.js
5
5
  function deepFreeze(value) {
6
6
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -1582,7 +1582,7 @@ function merchantProfileRecognizerById(id) {
1582
1582
  return typeof id === "string" ? MERCHANT_PROFILE_RECOGNIZERS.find((entry) => entry.id === id) ?? null : null;
1583
1583
  }
1584
1584
  var ADYEN_DOMAINS = ["adyen.com", "adyenpayments.com"];
1585
- var AGENTCARD_DOMAINS = ["agentcard.sh"];
1585
+ var AGENTCARD_DOMAINS = ["agentcard.sh", "agentcard.com"];
1586
1586
  var IPV4_HOST = /^\d{1,3}(?:\.\d{1,3}){3}$/;
1587
1587
  function underDomain(hostname, domain) {
1588
1588
  return hostname === domain || hostname.endsWith(`.${domain}`);
package/dist/amadeus.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /** How long after the pause a paused Amadeus SDK add may still be sent. */
2
2
  export declare const AMADEUS_SEND_WINDOW_MS = 20000;
3
+ /** How long after the pause a paused Wix tokenize request may still be sent, of the 30 seconds Wix's widget waits. */
4
+ export declare const WIX_PAYMENTS_SEND_WINDOW_MS = 20000;
3
5
  /**
4
6
  * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
5
7
  * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
@@ -9,12 +11,13 @@ export declare const AMADEUS_SEND_WINDOW_MS = 20000;
9
11
  */
10
12
  export declare function failsAsNetworkError(url: string): boolean;
11
13
  /** The processor a send window's events and stop cause name. */
12
- export type SendWindowProcessor = 'amadeus' | 'secure_acceptance';
14
+ export type SendWindowProcessor = 'amadeus' | 'secure_acceptance' | 'wix_payments';
13
15
  /** Why a send window stopped its attempt: the API confirmed the card never left the device and never can. */
14
16
  export type SendWindowClosed = `${SendWindowProcessor}_send_window_closed`;
15
17
  /**
16
18
  * The send window for a request paused under a preparation for `psp`, or null when it has none: a
17
- * prepared Amadeus SDK add, and a prepared CyberSource Secure Acceptance token create, each 20 seconds.
19
+ * prepared Amadeus SDK add, a prepared CyberSource Secure Acceptance token create and a prepared Wix
20
+ * tokenize request, each 20 seconds.
18
21
  */
19
22
  export declare function preparedSendWindowMs(psp: string | undefined, url: string): number | null;
20
23
  /** The processor a prepared request's send window names in its events, or null when it has none. */
package/dist/amadeus.js CHANGED
@@ -14,6 +14,11 @@
14
14
  // without a word. A token CyberSource creates after that point is one the page never reads, so a
15
15
  // paused token create gets the same 20 second window (cybersource-secure-acceptance.ts).
16
16
  //
17
+ // Wix's payment widget fails the payment 30 seconds after it asks Wix Cashier's card frame for a
18
+ // token (cashier-payments-widget 1.4964.0), and the merchant's page charges only a token the frame
19
+ // handed back in time. A token Wix mints after that point is one no charge ever names, so a paused
20
+ // tokenize request gets the same 20 second window.
21
+ //
17
22
  // So when the window closes and no answer is being handed to the page yet, the adapter asks for that
18
23
  // cancel. Confirmed: nothing was sent and nothing can be, so the attempt stops, the page's request
19
24
  // fails (a Secure Acceptance frame gets the stopped page), and the checkout reads failed. Not
@@ -24,13 +29,17 @@
24
29
  // request can bind it, nothing can be sent; when a request already holds it, that authorization gets
25
30
  // the same cancel and the same rule, and when the API confirms neither, the attempt keeps waiting. The
26
31
  // Data Collection Page's store has no client timeout and gets no window. The window's events name the
27
- // processor: `amadeus_send_window_closed` and `amadeus_send_window_unconfirmed`, or
28
- // `secure_acceptance_send_window_closed` and `secure_acceptance_send_window_unconfirmed`.
32
+ // processor: `amadeus_send_window_closed` and `amadeus_send_window_unconfirmed`,
33
+ // `secure_acceptance_send_window_closed` and `secure_acceptance_send_window_unconfirmed`, or
34
+ // `wix_payments_send_window_closed` and `wix_payments_send_window_unconfirmed`.
29
35
  import { amadeusCardUrl } from './amadeus-checkout.generated.js';
30
36
  import { isSecureAcceptanceTokenRequest } from './cybersource-secure-acceptance.generated.js';
31
37
  import { SECURE_ACCEPTANCE_PSP, SECURE_ACCEPTANCE_SEND_WINDOW_MS } from './cybersource-secure-acceptance.js';
38
+ import { WIX_PAYMENTS_PSP, isWixPaymentsTokenizeUrl } from './wix-payments.generated.js';
32
39
  /** How long after the pause a paused Amadeus SDK add may still be sent. */
33
40
  export const AMADEUS_SEND_WINDOW_MS = 20_000;
41
+ /** How long after the pause a paused Wix tokenize request may still be sent, of the 30 seconds Wix's widget waits. */
42
+ export const WIX_PAYMENTS_SEND_WINDOW_MS = 20_000;
34
43
  /**
35
44
  * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
36
45
  * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
@@ -43,7 +52,8 @@ export function failsAsNetworkError(url) {
43
52
  }
44
53
  /**
45
54
  * The send window for a request paused under a preparation for `psp`, or null when it has none: a
46
- * prepared Amadeus SDK add, and a prepared CyberSource Secure Acceptance token create, each 20 seconds.
55
+ * prepared Amadeus SDK add, a prepared CyberSource Secure Acceptance token create and a prepared Wix
56
+ * tokenize request, each 20 seconds.
47
57
  */
48
58
  export function preparedSendWindowMs(psp, url) {
49
59
  if (psp === 'amadeus_checkout')
@@ -58,10 +68,14 @@ export function preparedSendWindowMs(psp, url) {
58
68
  }
59
69
  return tokenCreate ? SECURE_ACCEPTANCE_SEND_WINDOW_MS : null;
60
70
  }
71
+ if (psp === WIX_PAYMENTS_PSP)
72
+ return isWixPaymentsTokenizeUrl(url) ? WIX_PAYMENTS_SEND_WINDOW_MS : null;
61
73
  return null;
62
74
  }
63
75
  /** The processor a prepared request's send window names in its events, or null when it has none. */
64
76
  export function sendWindowProcessor(psp) {
77
+ if (psp === WIX_PAYMENTS_PSP)
78
+ return 'wix_payments';
65
79
  return psp === 'amadeus_checkout' ? 'amadeus' : psp === SECURE_ACCEPTANCE_PSP ? 'secure_acceptance' : null;
66
80
  }
67
81
  /** The send window for a prepared Amadeus SDK add, or null: preparedSendWindowMs for Amadeus alone. */