@agent-cards/sdk 0.23.19 → 0.23.20

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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/PREFLIGHT.md +2 -0
  3. package/README.md +34 -4
  4. package/dist/amadeus.d.ts +4 -2
  5. package/dist/amadeus.js +16 -3
  6. package/dist/buy.d.ts +84 -2
  7. package/dist/buy.js +16 -1
  8. package/dist/card-endpoint-facts.d.ts +2 -1
  9. package/dist/card-endpoint-facts.js +18 -9
  10. package/dist/card-endpoint.d.ts +20 -4
  11. package/dist/card-endpoint.js +38 -4
  12. package/dist/card-fields.generated.js +483 -17
  13. package/dist/cdp.d.ts +29 -0
  14. package/dist/cdp.js +302 -18
  15. package/dist/client.d.ts +30 -4
  16. package/dist/client.js +128 -13
  17. package/dist/hipay.generated.d.ts +56 -0
  18. package/dist/hipay.generated.js +389 -0
  19. package/dist/hold.d.ts +180 -0
  20. package/dist/hold.js +264 -0
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.js +1 -0
  23. package/dist/lifecycle.d.ts +10 -0
  24. package/dist/lifecycle.js +21 -0
  25. package/dist/merchant-card-endpoints.generated.js +102 -11
  26. package/dist/paddle-vgs.generated.d.ts +3 -2
  27. package/dist/paddle-vgs.generated.js +9 -5
  28. package/dist/pre-claim.d.ts +14 -0
  29. package/dist/pre-claim.js +76 -3
  30. package/dist/prepared-processor.d.ts +6 -2
  31. package/dist/prepared-processor.js +18 -2
  32. package/dist/primer.generated.js +510 -44
  33. package/dist/quickpay.d.ts +44 -0
  34. package/dist/quickpay.js +65 -0
  35. package/dist/stripe-checkout.generated.js +124 -2
  36. package/dist/twoc2p.d.ts +54 -0
  37. package/dist/twoc2p.generated.d.ts +33 -0
  38. package/dist/twoc2p.generated.js +1145 -0
  39. package/dist/twoc2p.js +85 -0
  40. package/dist/voice.d.ts +16 -13
  41. package/dist/voice.js +13 -10
  42. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: f3437a15e11b72b9958179cc9610fdafb411cc5db76be536af62c08360a45575
3
+ // artifact-sha256: 20dc16205adc94410b425b342c7c54fce24ec95960fb8a0ee2a1558ba9d96dea
4
4
  // src/paddle-vgs.js
5
5
  var PADDLE_VGS_PSP = "paddle_vgs";
6
6
  var PADDLE_VGS_CAPABILITY = "paddle_vgs_cards";
@@ -135,6 +135,7 @@ var pin = (fields) => Object.freeze({
135
135
  origins: Object.freeze([...fields.origins]),
136
136
  sellerClaim: fields.sellerClaim ? Object.freeze({ ...fields.sellerClaim }) : null
137
137
  });
138
+ var PADDLE_VGS_ANY_SELLER = true;
138
139
  var PADDLE_VGS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
139
140
  pin({ id: "rectangle_pro", merchant: "Rectangle Pro", origins: ["https://rectangleapp.com"], sellerClaim: null })
140
141
  ]);
@@ -143,14 +144,17 @@ function paddleVgsMerchantPin(merchantOrigin, pins = PADDLE_VGS_MERCHANT_PINS) {
143
144
  return null;
144
145
  return pins.find((entry) => !!entry && Array.isArray(entry.origins) && entry.origins.includes(merchantOrigin)) ?? null;
145
146
  }
146
- function paddleVgsMerchantRefusal(environment, merchantOrigin, authorization, pins = PADDLE_VGS_MERCHANT_PINS) {
147
+ var SELLER_ORIGIN = /^https:\/\/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
148
+ var SELLER_ORIGIN_LIMIT = 261;
149
+ function paddleVgsMerchantRefusal(environment, merchantOrigin, authorization, pins = PADDLE_VGS_MERCHANT_PINS, anySeller = PADDLE_VGS_ANY_SELLER) {
147
150
  if (environment === "sandbox")
148
151
  return null;
149
152
  if (environment !== "production")
150
153
  return "unsupported_environment";
151
154
  const found = paddleVgsMerchantPin(merchantOrigin, pins);
152
- if (!found)
153
- return "paddle_vgs_merchant_unreviewed";
155
+ if (!found) {
156
+ return anySeller === true && typeof merchantOrigin === "string" && merchantOrigin.length <= SELLER_ORIGIN_LIMIT && SELLER_ORIGIN.test(merchantOrigin) ? null : "paddle_vgs_merchant_unreviewed";
157
+ }
154
158
  if (found.sellerClaim && authorization !== void 0) {
155
159
  const claims = bearerClaims(authorization);
156
160
  if (!claims || claims[found.sellerClaim.name] !== found.sellerClaim.value)
@@ -405,4 +409,4 @@ function paddleVgsPayVerdict(request, approved) {
405
409
  card.metadata[key] = facts[key];
406
410
  return Object.freeze({ verdict: "continue", body: JSON.stringify(value) });
407
411
  }
408
- export { PADDLE_VGS_CAPABILITY, PADDLE_VGS_CARDS_URLS, PADDLE_VGS_CARD_ID_WINDOW_MS, PADDLE_VGS_CARD_NETWORKS, PADDLE_VGS_CONTENT_TYPE, PADDLE_VGS_MERCHANT_PINS, PADDLE_VGS_OPERATION, PADDLE_VGS_PSP, PADDLE_VGS_REFUSAL_CODES, injectPaddleVgsCard, isPaddleVgsCardsUrl, isPreparedPaddleVgsRequest, paddleVgsAnswerOutcome, paddleVgsBodyVerdict, paddleVgsCardFacts, paddleVgsCardFactsAgree, paddleVgsCardFactsOf, paddleVgsCardRefusal, paddleVgsEnvironment, paddleVgsMerchantPin, paddleVgsMerchantRefusal, paddleVgsPayCarriesStoredCard, paddleVgsPayTarget, paddleVgsPayVerdict, paddleVgsRefusalCode, paddleVgsRefusalMessage, paddleVgsRequestRefusal, paddleVgsSellerClaimsPinned, paddleVgsStoredCardRefusal, paddleVgsTypedCardRefusal };
412
+ export { PADDLE_VGS_ANY_SELLER, PADDLE_VGS_CAPABILITY, PADDLE_VGS_CARDS_URLS, PADDLE_VGS_CARD_ID_WINDOW_MS, PADDLE_VGS_CARD_NETWORKS, PADDLE_VGS_CONTENT_TYPE, PADDLE_VGS_MERCHANT_PINS, PADDLE_VGS_OPERATION, PADDLE_VGS_PSP, PADDLE_VGS_REFUSAL_CODES, injectPaddleVgsCard, isPaddleVgsCardsUrl, isPreparedPaddleVgsRequest, paddleVgsAnswerOutcome, paddleVgsBodyVerdict, paddleVgsCardFacts, paddleVgsCardFactsAgree, paddleVgsCardFactsOf, paddleVgsCardRefusal, paddleVgsEnvironment, paddleVgsMerchantPin, paddleVgsMerchantRefusal, paddleVgsPayCarriesStoredCard, paddleVgsPayTarget, paddleVgsPayVerdict, paddleVgsRefusalCode, paddleVgsRefusalMessage, paddleVgsRequestRefusal, paddleVgsSellerClaimsPinned, paddleVgsStoredCardRefusal, paddleVgsTypedCardRefusal };
@@ -99,6 +99,8 @@ export interface PreClaimContext {
99
99
  verifoneProfileOf?(url: string): VerifoneProfile | null;
100
100
  cardOnFilePolicy?(url: string, method?: string): string | null;
101
101
  withoutCard?(url: string, body: string | null | undefined): 'continue' | 'refuse' | null;
102
+ /** VaultClient.recognizesProcessor: whether the synced registry serves this processor. */
103
+ recognizesProcessor?(psp: string): boolean;
102
104
  /** VaultClient.sendEbanxFollowUp: a send an approved EBANX token request covers, from the cardholder's device. */
103
105
  sendEbanxFollowUp?(authorizationId: string, request: {
104
106
  url: string;
@@ -251,11 +253,23 @@ export declare function isArmedCreditguardCall(vault: {
251
253
  } | undefined, url: string): boolean;
252
254
  export declare const ekashuPreClaim: PreClaimGate;
253
255
  export declare const redsysPreClaim: PreClaimGate;
256
+ export declare const quickpayPreClaim: PreClaimGate;
254
257
  export declare const paypalHostedFieldsPreClaim: PreClaimGate;
255
258
  export declare const paypalCardFormsPreClaim: PreClaimGate;
256
259
  export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;
257
260
  export declare const worldlineMyCheckoutPreClaim: PreClaimGate;
258
261
  export declare const paddleVgsPayPreClaim: PreClaimGate;
262
+ export type HipayPreClaimRefusal = 'hipay_number_only' | 'hipay_update_refused';
263
+ export declare const hipayPreClaim: PreClaimGate;
264
+ /**
265
+ * Whether attachToPlaywright routes `url` to the gates for HiPay: any request to HiPay's two vault hosts, once the
266
+ * synced registry serves HiPay, as attachToCdp arms both hosts from the recognizer. Playwright's route matcher sees
267
+ * only the URL and the recognizer takes the token create alone, so without this /update would never reach
268
+ * hipayPreClaim there. Any other request to those hosts goes on untouched.
269
+ */
270
+ export declare function routesHipayVault(vault: {
271
+ recognizesProcessor?: (psp: string) => boolean;
272
+ } | null | undefined, url: string): boolean;
259
273
  export declare const ebanxPreClaim: PreClaimGate;
260
274
  /** The processor gates, in order. A new family adds one entry here; the terminal
261
275
  * arbiter runs after all of them and is not part of this list. A gate appended
package/dist/pre-claim.js CHANGED
@@ -80,11 +80,13 @@ import { PAYRAILS_HOLDING_REASONS, PAYRAILS_SESSION_MESSAGE, isPayrailsHost, isP
80
80
  import { classifyVerifoneProfileRequest, verifoneTemplatedUrl } from './verifone.js';
81
81
  import { ekashuEntryUrl, isEkashuEntry, isEkashuHost } from './ekashu.js';
82
82
  import { isRedsysEntry, isRedsysHost, redsysEntryUrl } from './redsys.js';
83
+ import { isQuickpayCardLookup, isQuickpayEntry, quickpayEntryUrl } from './quickpay.js';
83
84
  import { PAYPAL_HOSTED_FIELDS_REASON, isPaypalHostedFieldsConfirm, paypalHostedFieldsBody } from './paypal-hosted-fields.js';
84
85
  import { PAYPAL_CARD_FIELDS_REASON, PAYPAL_GUEST_CHECKOUT_REASON, isPaypalCardFieldsConfirm, isPaypalGraphql, paypalCardFieldsBody, paypalGraphqlCard, paypalGraphqlNamesCardOperation, } from './paypal-card-forms.js';
85
86
  import { CYBERSOURCE_SECURE_ACCEPTANCE_REASON, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, cybersourceSecureAcceptanceRequest, isCybersourceSecureAcceptanceUrl, isSecureAcceptanceFramePost, } from './cybersource-secure-acceptance.js';
86
87
  import { isWorldlineMyCheckoutEndpoint } from './worldline-mycheckout.js';
87
88
  import { paddleVgsPayEventUrl } from './paddle-vgs-pay.js';
89
+ import { HIPAY_PSP, HIPAY_TOKEN_URLS, HIPAY_UPDATE_PATH, HIPAY_VAULT_HOSTS, hipayNumberOnlyRequest } from './hipay.generated.js';
88
90
  import { EBANX_RESEND_REASON, EbanxFollowUpError, ebanxResendRefusalOf, isEbanxResendUrl, } from './ebanx.js';
89
91
  /**
90
92
  * The URL an event may name for a request. For an armed merchant profile's
@@ -1595,7 +1597,8 @@ export const ekashuPreClaim = (ctx) => {
1595
1597
  return undefined;
1596
1598
  return processorPageAbort(ctx);
1597
1599
  };
1598
- // The stop for a card post into a processor's own page that only the cardholder's device may pay (NMI's, Redsys's).
1600
+ // The stop for a card post into a processor's own page that only the cardholder's device may pay (NMI's, Redsys's,
1601
+ // QuickPay's).
1599
1602
  async function processorPageAbort(ctx) {
1600
1603
  const { url, method } = ctx.request;
1601
1604
  ctx.preparationGate.invalidate('unsupported_checkout');
@@ -1628,6 +1631,30 @@ export const redsysPreClaim = (ctx) => {
1628
1631
  return undefined;
1629
1632
  return processorPageAbort(ctx);
1630
1633
  };
1634
+ // QuickPay's hosted payment window (quickpay.ts). Once this build's registry serves QuickPay's entry (a capability
1635
+ // the API serves only to a company Agentcard turned QuickPay on for), every request to QuickPay's host pauses, and
1636
+ // this gate judges the POSTs and the window's card lookup:
1637
+ // - the merchant's entry (the host's root, no query) defers, and the terminal arbiter pauses it for the claim
1638
+ // flow like any card request: the cardholder's device pays it;
1639
+ // - every other POST to QuickPay (the window's card post, its fee lookup, its wallet token post, its 3-D Secure
1640
+ // step, and the framed twin of the entry, whose window asks for a card) aborts as an unsupported checkout,
1641
+ // and so does the window's GET that looks up the typed card's first digits, so QuickPay never sees the card
1642
+ // the agent typed. The agent's browser only reaches QuickPay's window when the entry was not paused (an
1643
+ // attachment made too late, say), and then only the cardholder's device can pay.
1644
+ // Any other GET (the window itself, its scripts and images) is not this gate's and continues. With QuickPay not
1645
+ // served, the entry is no card request, the gate defers, and every request continues as before. Synchronous
1646
+ // until it must abort, like every gate. Exported for the gate registry's tests.
1647
+ export const quickpayPreClaim = (ctx) => {
1648
+ const { url, method } = ctx.request;
1649
+ if (String(method).toUpperCase() !== 'POST' && !isQuickpayCardLookup(url, method))
1650
+ return undefined;
1651
+ const entry = quickpayEntryUrl(url);
1652
+ if (!entry || !ctx.vault.isCardRequest(entry, 'POST'))
1653
+ return undefined;
1654
+ if (isQuickpayEntry(url, method))
1655
+ return undefined;
1656
+ return processorPageAbort(ctx);
1657
+ };
1631
1658
  // PayPal's legacy Hosted Fields (paypal-hosted-fields.ts). Its tokenization frame posts the card the
1632
1659
  // agent typed to the Orders v2 confirm-payment-source on cors.api.paypal.com (or its sandbox), which
1633
1660
  // no Vault mode takes over, so every company's adapters hand each POST there to this gate:
@@ -1952,6 +1979,52 @@ async function paddleVgsPayContinued(ctx, body) {
1952
1979
  fields: ['card_first_six', 'card_last_four', 'expiry_month', 'expiry_year', 'card_brand'] } });
1953
1980
  return { kind: 'continue' };
1954
1981
  }
1982
+ // HiPay's hosted fields (payment-core hipay.js). The controller frame posts the card number alone as soon as the typed
1983
+ // number is valid, before Pay, and posts /rest/v2/token/update with a token once it holds one. Neither is this lane's
1984
+ // card request. The number-only post fails here as a network error, so the frame keeps the number and Pay sends one
1985
+ // complete create, the request a preparation binds. /update fails the same way, so the page's placeholder code and
1986
+ // expiry never ride under a token HiPay minted for the real card (the frame holds one only when an answer reached it
1987
+ // after the page gave up). Both fail before the preparation claim reads them: a ready preparation is neither spent
1988
+ // nor invalidated, and nothing reaches the API. Only while the synced registry serves HiPay (a build that declared
1989
+ // hipay_vault_token, for a company Agentcard turned HiPay on for); for anyone else HiPay's traffic is left as it was.
1990
+ const HIPAY_UPDATE_URLS = Object.values(HIPAY_TOKEN_URLS).map((url) => `${new URL(url).origin}${HIPAY_UPDATE_PATH}`);
1991
+ export const hipayPreClaim = (ctx) => {
1992
+ const { url, method } = ctx.request;
1993
+ if (typeof method !== 'string' || method.toUpperCase() !== 'POST' || ctx.vault.recognizesProcessor?.(HIPAY_PSP) !== true)
1994
+ return undefined;
1995
+ if (HIPAY_UPDATE_URLS.includes(url))
1996
+ return hipayRefused(ctx, 'hipay_update_refused');
1997
+ let body;
1998
+ // A reader that throws (Playwright's postData() can) proves nothing: the request is judged later, as any other.
1999
+ try {
2000
+ body = ctx.request.body;
2001
+ }
2002
+ catch {
2003
+ return undefined;
2004
+ }
2005
+ return hipayNumberOnlyRequest(url, method, body) ? hipayRefused(ctx, 'hipay_number_only') : undefined;
2006
+ };
2007
+ /**
2008
+ * Whether attachToPlaywright routes `url` to the gates for HiPay: any request to HiPay's two vault hosts, once the
2009
+ * synced registry serves HiPay, as attachToCdp arms both hosts from the recognizer. Playwright's route matcher sees
2010
+ * only the URL and the recognizer takes the token create alone, so without this /update would never reach
2011
+ * hipayPreClaim there. Any other request to those hosts goes on untouched.
2012
+ */
2013
+ export function routesHipayVault(vault, url) {
2014
+ let host;
2015
+ try {
2016
+ host = new URL(url).hostname;
2017
+ }
2018
+ catch {
2019
+ return false;
2020
+ }
2021
+ return Object.keys(HIPAY_VAULT_HOSTS).includes(host) && vault?.recognizesProcessor?.(HIPAY_PSP) === true;
2022
+ }
2023
+ async function hipayRefused(ctx, reason) {
2024
+ ctx.onEvent?.({ type: 'blocked', detail: reason });
2025
+ await ctx.effects.abort();
2026
+ return { kind: 'abort' };
2027
+ }
1955
2028
  // EBANX after its card token (ebanx.ts, payment-core ebanx.js). Once the cardholder's device has sent the card to
1956
2029
  // /ws/token, EBANX's hosted payment page and EBANX.js send the card the page holds again: its 3-D Secure calls post
1957
2030
  // the card, and the hosted page's confirm posts its code beside EBANX's token. On a page this SDK is attached to that
@@ -2147,8 +2220,8 @@ async function unsupportedContinue(ctx) {
2147
2220
  * arbiter runs after all of them and is not part of this list. A gate appended
2148
2221
  * after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
2149
2222
  * pauses each one itself. */
2150
- export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, paypalHostedFieldsPreClaim,
2151
- paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim];
2223
+ export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, paypalHostedFieldsPreClaim,
2224
+ paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, hipayPreClaim];
2152
2225
  /** Run each gate in order; the first to return a decision wins. If none does,
2153
2226
  * the terminal arbiter decides between continue, abort (unsupported) and pause.
2154
2227
  * Returns synchronously while every gate defers synchronously (an ordinary card
@@ -24,8 +24,12 @@
24
24
  * wix_payments: prepared only. Wix's payment widget fails the payment 30 seconds after it asks Wix
25
25
  * Cashier's card frame for a token, too soon for an approval after Pay. Its one environment is
26
26
  * production: Wix's tokenizer has no test host.
27
+ *
28
+ * hipay: prepared only. The merchant's page gives HiPay's hosted fields 20 seconds after Pay, too soon for an
29
+ * approval after Pay. Its environments are its two vault hosts: secure2-vault (production) and
30
+ * stage-secure2-vault (sandbox).
27
31
  */
28
- export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments';
32
+ export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments' | 'hipay';
29
33
  export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
30
34
  /**
31
35
  * How the approved card reaches the processor: the device's own request (token), or
@@ -62,7 +66,7 @@ export declare function preparedApprovalAnswersRetry(psp: string): boolean;
62
66
  * its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
63
67
  * profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
64
68
  * live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
65
- * sandbox-vault is test.
69
+ * sandbox-vault is test. So are HiPay's two vault hosts: secure2-vault is live, stage-secure2-vault is test.
66
70
  */
67
71
  export declare function validPreparationEnvironment(psp: string, environment: string): boolean;
68
72
  /**
@@ -15,6 +15,7 @@ import { isPreparedVerifoneRequest } from './verifone.js';
15
15
  import { isPreparedSecureAcceptanceRequest, secureAcceptanceEnvironment, secureAcceptancePreparationUrl, secureAcceptanceRequestRefusal, } from './cybersource-secure-acceptance.generated.js';
16
16
  import { PADDLE_VGS_CARDS_URLS, isPreparedPaddleVgsRequest } from './paddle-vgs.generated.js';
17
17
  import { WIX_PAYMENTS_TOKENIZE_URL, isPreparedWixPaymentsRequest } from './wix-payments.generated.js';
18
+ import { HIPAY_TOKEN_URLS, hipayRequestRefusal, hipayTokenEnvironment, isPreparedHipayRequest } from './hipay.generated.js';
18
19
  export function preparationMode(psp) {
19
20
  return psp === 'adyen' || psp === 'fiserv' || psp === 'verifone' ? 'cse' : 'token';
20
21
  }
@@ -49,7 +50,7 @@ export function preparedApprovalAnswersRetry(psp) {
49
50
  * its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
50
51
  * profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
51
52
  * live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
52
- * sandbox-vault is test.
53
+ * sandbox-vault is test. So are HiPay's two vault hosts: secure2-vault is live, stage-secure2-vault is test.
53
54
  */
54
55
  export function validPreparationEnvironment(psp, environment) {
55
56
  if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
@@ -58,7 +59,7 @@ export function validPreparationEnvironment(psp, environment) {
58
59
  if (psp === 'wix_payments')
59
60
  return environment === 'production';
60
61
  return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv', 'cybersource_flex', 'aci', 'creditguard', 'worldpay_eprotect', 'amadeus_checkout', 'verifone',
61
- 'cybersource_secure_acceptance', 'paddle_vgs'].includes(psp) && ['production', 'sandbox'].includes(environment);
62
+ 'cybersource_secure_acceptance', 'paddle_vgs', 'hipay'].includes(psp) && ['production', 'sandbox'].includes(environment);
62
63
  }
63
64
  /**
64
65
  * ACI's prepared endpoint, the literal the API names (backend checkout-prepared-processor.ts): its
@@ -106,6 +107,9 @@ export function preparationEndpoint(psp, environment) {
106
107
  // Wix Payments: the tokenize URL, the only URL the claim takes for it.
107
108
  if (psp === 'wix_payments')
108
109
  return WIX_PAYMENTS_TOKENIZE_URL;
110
+ // HiPay: the token create on the environment's vault, the only URL the claim takes for it.
111
+ if (psp === 'hipay')
112
+ return HIPAY_TOKEN_URLS[environment];
109
113
  // A Verifone endpoint is its reviewed profile's leg, never one per environment (verifone.ts).
110
114
  if (psp === 'verifone')
111
115
  throw new Error('unsupported_preparation_processor');
@@ -263,6 +267,11 @@ export function matchesPreparedRequest(psp, environment, requestUrl, method, bod
263
267
  // site's app instance and the card frame's body), the rule the API and the Vault bind with too.
264
268
  if (psp === 'wix_payments')
265
269
  return isPreparedWixPaymentsRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
270
+ // HiPay: the environment's own vault and payment-core's whole request rule (a JSON content type, a public username of
271
+ // that environment and a complete create, never the hosted fields' number-only post), the rule the API and the Vault
272
+ // bind with too.
273
+ if (psp === 'hipay')
274
+ return isPreparedHipayRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
266
275
  if (psp === 'creditguard')
267
276
  return matchesPreparedCreditguard(environment, requestUrl, body, headers, binding);
268
277
  // A Verifone request is judged only through the profile its preparation names (matchesPreparation).
@@ -423,6 +432,13 @@ export function preparedRequestRefusal(psp, environment, requestUrl, body, heade
423
432
  const reason = secureAcceptanceClaimRefusal(requestUrl, body, headers, merchantOrigin, currency);
424
433
  return reason === null ? 'checkout_changed' : `secure_acceptance_${reason}`;
425
434
  }
435
+ // A HiPay token create on the prepared environment's vault names what payment-core's request rule refused
436
+ // (hipay_keeps_card, hipay_headers_refused, ...); another vault or another request is `checkout_changed`.
437
+ if (psp === 'hipay') {
438
+ if (hipayTokenEnvironment(requestUrl) !== environment)
439
+ return 'checkout_changed';
440
+ return hipayRequestRefusal({ url: requestUrl, method: 'POST', headers, body: body ?? null }) ?? 'checkout_changed';
441
+ }
426
442
  if (psp !== 'amadeus_checkout' || amadeusEnvironment(requestUrl) !== environment)
427
443
  return 'checkout_changed';
428
444
  const merchantHost = merchantHostOf(merchantOrigin);