@agent-cards/sdk 0.23.18 → 0.23.19

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 CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Answer a Datatrans form's second card post from a token answer that carries no `cardInfo`, or a `cardInfo` with the `accountType` and `binLength` fields Datatrans documents. Datatrans's card frame reads both answers as a success, and the API records them once it runs this release's checkout rules. An earlier SDK version still hands the first answer to the page, because it passes on whatever the API stored, but it sends the page's next post of the same form to the cardholder as a new approval.
6
+
5
7
  - Finish a Worldpay eProtect checkout that your code resumes itself. With `attachToCdp(…, { pauseOnly: true })`, you create the authorization, read it, and call `controller.resume(read)`. The read carries the card registration as Agentcard stored it, bare JSON, and earlier releases handed exactly that to the merchant's paused registration script. Worldpay's script reads its answer only through the callback the request named, so it never received the registration: the page waited until the merchant's timeout, and the checkout read `outcome_unknown` with reason `merchant_request_aborted` after the cardholder had approved. The SDK now answers the resumed registration as it answers one it created itself, with the registration inside the request's own callback under Worldpay's script type. The SDK never hands the page a read that is not this request's registration, such as one already inside a callback or another request's answer: `resume` rejects with `PaymentOutcomeUnknownError`, reason `eprotect_registration_unconfirmed`, and the paused request fails. A checkout whose authorization the SDK creates was already answered this way and does not change. No API or Vault release is needed.
6
8
 
9
+ - Keep a SumUp checkout's id out of your events and error messages. SumUp's Payment Widget sends the card to `https://api.sumup.com/v0.2/checkouts/<checkout id>` with no cookie and no auth header, so that id opens the checkout, its amount and its merchant, to anyone who holds it. `redactUrl`, every event and every error message now show it as `{checkout}` on SumUp's API host, as in `https://api.sumup.com/v0.2/checkouts/{checkout}`, and drop the query as before. The SDK does not pause a SumUp payment yet. No API or Vault release is needed.
10
+
7
11
  - 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:
8
12
 
9
13
  ```text
@@ -141,6 +145,8 @@
141
145
 
142
146
  - Keep a processor's id out of your events and error messages however the URL spells the slashes in front of it. A path keeps a percent escape as it was written, so a slash can reach `redactUrl` as `%2F` or `%2f`, escaped twice as `%252F`, or doubled. Earlier releases showed the last digits of a Payfast payment, a CreditGuard transaction or a Gravy session written without its hyphens after an escaped slash, as in `https://payment.payfast.io/eng/method/CreditCard%{uuid}7f/pay`, and all of one written with its hyphens escaped, as of a Przelewy24 transaction's token. They showed a Stripe Checkout Session, a PayPal order, a GoPay card form's token, a Paddle checkout and a WSPay or Monri client secret whole behind a slash escaped twice or doubled, or behind a route whose own slash was escaped, a Lyra session behind an escaped `;` or `=`, and a Redsys session behind one escaped twice. `redactUrl`, every event and every error message now show each id as its label in every one of these spellings, as in `https://payment.payfast.io/eng/method/CreditCard%2F{uuid}/pay`. No API or Vault release is needed.
143
147
 
148
+ - Keep a processor's id out of `redactUrl`, your events and your error messages when text before the URL reads as a scheme. Earlier releases read `see:https://api.stripe.com/v1/payment_pages/<session id>/confirm` as a URL with no host, and `http:https://api.stripe.com/...` as a URL whose host is `https`, and showed the whole id in both: a Stripe Checkout Session, a Revolut order, a WSPay client secret and every other id `redactUrl` hides. A processor's URL inside another URL's path showed its id the same way, as did a second ACI checkout id after the first, and a KOMOJU URL showed the first characters of any longer id inside it. `redactUrl`, every event and every error message now hide a processor's id wherever the text names that processor's host, as in `see:https://api.stripe.com/v1/payment_pages/{session}/confirm`. Any other URL with a host reads as before. A URL with no host, such as `about:blank`, now reads as written up to its query, where earlier releases showed `nullblank`. No API or Vault release is needed.
149
+
144
150
  - 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.
145
151
 
146
152
  - 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.
@@ -153,6 +159,10 @@
153
159
 
154
160
  - 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.
155
161
 
162
+ - 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`. The SDK does not pause a Revolut payment yet. No API or Vault release is needed.
163
+
164
+ - 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.
165
+
156
166
  ## 0.23.0
157
167
 
158
168
  ### Upgrading from 0.22.0
package/README.md CHANGED
@@ -1600,8 +1600,9 @@ number and CVV are Datatrans's own iframes on `pay.datatrans.com`
1600
1600
  whole card in one request: `POST /upp/payment/SecureFields/paymentField`,
1601
1601
  form encoded, in TOKENIZE mode. The SDK pauses that request, the cardholder's
1602
1602
  device sends the real card to Datatrans, and the iframe receives Datatrans's
1603
- token (`transactionId`) and its `cardInfo`: brand, credit or debit, consumer
1604
- or corporate, issuing country and issuer, never a digit of the card.
1603
+ token (`transactionId`) and, when Datatrans sends it, the card's `cardInfo`:
1604
+ brand, credit or debit, consumer or corporate, issuing country, issuer,
1605
+ account type and BIN length, never a digit of the card.
1605
1606
 
1606
1607
  ```ts
1607
1608
  await vault.syncRegistry(); // the Datatrans recognizer is never in the built-in list
@@ -1641,7 +1642,8 @@ const checkout = await attachToPlaywright(page, {
1641
1642
  whenever a field loses focus or the expiry changes. Once a post was
1642
1643
  approved, a later post from the same iframe that differs from it only in
1643
1644
  the expiry (`expm`, `expy`) and the browser details is answered with the
1644
- same token and `cardInfo`: no second prompt, no second card sent. The
1645
+ same answer, the token and any `cardInfo` it came with: no second prompt,
1646
+ no second card sent. The
1645
1647
  adapters emit `repeat_answered` with the `authorizationId`; it is not a
1646
1648
  second payment and must not be counted as one. Any other change (a new
1647
1649
  `formId` from a reloaded iframe, another placeholder card or CVV, another
@@ -1767,6 +1769,13 @@ const checkout = await attachToPlaywright(page, {
1767
1769
  session is expected to last about as long from page load, so the approval
1768
1770
  has to land inside it. A 3-D Secure answer is never read as approved:
1769
1771
  reconcile that payment with the merchant.
1772
+ - Pelecard's code 302, "Debit was successful but merchant is not responding",
1773
+ is a payment that went through. The approval is recorded and the SDK reads
1774
+ `awaiting_merchant`, as for any approved Pelecard payment, until your
1775
+ `resolveMerchantResult` confirms the order with the merchant. When Pelecard
1776
+ names no landing page for a 302, Pelecard's page stays where it is and
1777
+ shows that text in its red error row with Pay enabled again. Go by the
1778
+ SDK's state, not that row, and never pay again on a new payment page.
1770
1779
 
1771
1780
  ### Pay a CreditGuard checkout
1772
1781
 
package/dist/aci.d.ts CHANGED
@@ -70,13 +70,6 @@ export declare function aciCardLegAnswer(response: {
70
70
  status: number;
71
71
  body: string;
72
72
  }): AciAnswer | null;
73
- /**
74
- * The URL with an ACI checkout id taken out of its path, or null for a URL that is not on one of
75
- * ACI's hosts under /v1/checkouts/. The id is the checkout's only capability: once the card-number
76
- * request carried the real card, anyone holding it can post /payment against that card for the
77
- * rest of the checkout's 30 minutes, so it never rides on an event.
78
- */
79
- export declare function redactAciCheckoutId(raw: string): string | null;
80
73
  /** How long the persistent-context engine probe (a CDP session opening) may take before it counts as no. */
81
74
  export declare const ACI_ENGINE_PROBE_MS = 5000;
82
75
  /**
package/dist/aci.js CHANGED
@@ -84,25 +84,6 @@ export function aciCardLegAnswer(response) {
84
84
  return null;
85
85
  return { status: response.status, headers: { 'content-type': 'application/json' }, body: rebuilt };
86
86
  }
87
- /**
88
- * The URL with an ACI checkout id taken out of its path, or null for a URL that is not on one of
89
- * ACI's hosts under /v1/checkouts/. The id is the checkout's only capability: once the card-number
90
- * request carried the real card, anyone holding it can post /payment against that card for the
91
- * rest of the checkout's 30 minutes, so it never rides on an event.
92
- */
93
- export function redactAciCheckoutId(raw) {
94
- let url;
95
- try {
96
- url = new URL(raw);
97
- }
98
- catch {
99
- return null;
100
- }
101
- if (!['eu-prod.oppwa.com', 'oppwa.com', 'eu-test.oppwa.com', 'test.oppwa.com'].includes(url.hostname))
102
- return null;
103
- const path = /^\/v1\/checkouts\/[^/]+(\/.*)?$/.exec(url.pathname);
104
- return path ? `${url.origin}/v1/checkouts/{checkoutId}${path[1] ?? ''}` : null;
105
- }
106
87
  /** How long the persistent-context engine probe (a CDP session opening) may take before it counts as no. */
107
88
  export const ACI_ENGINE_PROBE_MS = 5_000;
108
89
  /**