@agent-cards/sdk 0.23.9 → 0.23.10

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 (58) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/PREFLIGHT.md +7 -5
  3. package/README.md +181 -92
  4. package/dist/aci.d.ts +7 -5
  5. package/dist/aci.generated.d.ts +2 -1
  6. package/dist/aci.generated.js +14 -4
  7. package/dist/aci.js +28 -7
  8. package/dist/amadeus-checkout.generated.js +2 -2
  9. package/dist/builtin-registry.generated.js +1 -1
  10. package/dist/card-fields.generated.js +163 -9
  11. package/dist/cdp.js +79 -34
  12. package/dist/client.d.ts +61 -31
  13. package/dist/client.js +99 -42
  14. package/dist/creditguard.generated.d.ts +1 -1
  15. package/dist/creditguard.generated.js +1 -3
  16. package/dist/cse-body.d.ts +7 -6
  17. package/dist/cse-body.js +8 -7
  18. package/dist/datatrans.generated.js +8 -5
  19. package/dist/elavon-converge.d.ts +1 -1
  20. package/dist/elavon-converge.generated.js +7 -4
  21. package/dist/elavon-converge.js +4 -3
  22. package/dist/fiserv.d.ts +9 -5
  23. package/dist/fiserv.generated.d.ts +3 -3
  24. package/dist/fiserv.generated.js +50 -20
  25. package/dist/fiserv.js +10 -6
  26. package/dist/payrails.d.ts +78 -18
  27. package/dist/payrails.generated.d.ts +12 -2
  28. package/dist/payrails.generated.js +213 -18
  29. package/dist/payrails.js +165 -44
  30. package/dist/pre-claim.js +51 -29
  31. package/dist/preflight-capabilities.generated.d.ts +0 -106
  32. package/dist/preflight-capabilities.generated.js +0 -153
  33. package/dist/preflight-catalog.json +61 -181
  34. package/dist/preflight-schemas.json +6 -6
  35. package/dist/preflight.generated.d.ts +0 -106
  36. package/dist/preflight.generated.js +27 -15
  37. package/dist/preparation.d.ts +2 -0
  38. package/dist/preparation.js +4 -2
  39. package/dist/prepared-processor.d.ts +19 -5
  40. package/dist/prepared-processor.js +21 -5
  41. package/dist/primer.generated.d.ts +5 -1
  42. package/dist/primer.generated.js +200 -33
  43. package/dist/registry.d.ts +18 -12
  44. package/dist/registry.js +11 -8
  45. package/dist/shiji-sts.d.ts +24 -22
  46. package/dist/shiji-sts.generated.d.ts +1 -1
  47. package/dist/shiji-sts.generated.js +12 -8
  48. package/dist/shiji-sts.js +49 -46
  49. package/dist/stripe-checkout.generated.js +146 -49
  50. package/dist/verifone.generated.js +192 -17
  51. package/dist/verifone.js +1 -1
  52. package/dist/wspay.d.ts +17 -16
  53. package/dist/wspay.generated.d.ts +6 -1
  54. package/dist/wspay.generated.js +13 -3
  55. package/dist/wspay.js +9 -11
  56. package/examples/preflight/kernel-native/README.md +1 -1
  57. package/examples/preflight/kernel-native/inventory.json +1 -19
  58. package/package.json +3 -3
package/dist/client.js CHANGED
@@ -13,7 +13,7 @@ import { merchantSessionCapture } from './merchant-session-probe.js';
13
13
  import { creditguardPageProcessUrl, creditguardPpDomainHost, creditguardPreparationEnvironment, creditguardProcessTxId, sanitizeCreditguardResponse, } from './creditguard.generated.js';
14
14
  import { CONVERGE_CAPABILITY } from './elavon-converge.js';
15
15
  import { SHIJI_STS_CAPABILITY, SHIJI_STS_PSP, isShijiStsServedCompanion, isShijiStsServedSubstitution } from './shiji-sts.js';
16
- import { AMADEUS_CHECKOUT_CAPABILITY } from './amadeus-checkout.generated.js';
16
+ import { AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP } from './amadeus-checkout.generated.js';
17
17
  import { classifyStripeCheckoutRequest, encodeStripeCheckoutContext, hasStripeCheckoutMarker, parseStripeCheckoutContext, parseStripeCheckoutResponse, STRIPE_CHECKOUT_CONTEXT_HEADER, } from './stripe-checkout.generated.js';
18
18
  import { VoiceModule } from './voice.js';
19
19
  import { BuyModule } from './buy.js';
@@ -29,7 +29,7 @@ import { merchantCardEndpointFactsRefusal as sharedFactsRefusal, readMerchantCar
29
29
  import { DATATRANS_CAPABILITY } from './datatrans.js';
30
30
  import { PELECARD_CAPABILITY, PELECARD_PSP } from './pelecard.js';
31
31
  import { PRIMER_CAPABILITY, PRIMER_PSP, primerTokenAnswer } from './primer.js';
32
- import { PAYRAILS_CAPABILITY, payrailsSaveAnswer } from './payrails.js';
32
+ import { PAYRAILS_CAPABILITY, isPayrailsPaymentUrl, payrailsAnswer } from './payrails.js';
33
33
  import { WSPAY_CAPABILITY, WSPAY_PSP } from './wspay.js';
34
34
  import { SECURE_ACCEPTANCE_CAPABILITY, SECURE_ACCEPTANCE_FAST_POLL_MS, SECURE_ACCEPTANCE_PSP, SECURE_ACCEPTANCE_REPLY_WINDOW_MS, secureAcceptanceCheckoutProfile, secureAcceptanceCheckoutRefusal, secureAcceptanceFrameAnswer, } from './cybersource-secure-acceptance.js';
35
35
  /**
@@ -37,7 +37,7 @@ import { SECURE_ACCEPTANCE_CAPABILITY, SECURE_ACCEPTANCE_FAST_POLL_MS, SECURE_AC
37
37
  * only recognizers in these modes, so a request this build cannot complete
38
38
  * is never paused) and sent on every create. `device_encrypt`: the adapters
39
39
  * capture the Payrails session key the page's init payload names (payrails.ts),
40
- * and the cardholder's device encrypts and sends the save.
40
+ * and the cardholder's device encrypts and sends the save or card-form payment.
41
41
  */
42
42
  export const SUPPORTED_MODES = ['token', 'cse', 'hosted_form', 'device_encrypt'];
43
43
  /**
@@ -107,14 +107,17 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
107
107
  * `primer_payment_instruments`: Primer's card tokenization, which this build
108
108
  * judges before it pauses (primer.ts) and hands back to the page only as a
109
109
  * single-use token. A merchant's client session can save the card after the
110
- * payment with no sign in that request, so the API creates a Primer
111
- * authorization only for a test-mode client and refuses a live one (400
112
- * invalid_primer_request, live_keep_on_file) until the cardholder can consent
113
- * to that save; this build then aborts the paused request with nothing sent. A
114
- * gated recognizer never sits in BUILTIN_REGISTRY, so it is paused only after a
115
- * sync.
116
- * `payrails_device_encrypt`: Payrails' card-form save, which this build pauses
117
- * only once it has bound the save to a captured session (payrails.ts). A gated
110
+ * payment with no sign in that request, so the API creates a live Primer
111
+ * authorization only when it names the checkout page's https origin
112
+ * (checkout_origin, which this build sends from the page's origin): the
113
+ * approval says the merchant keeps the card on file, under the merchant name
114
+ * the create sent, which Agentcard cannot confirm, and pays only with a card
115
+ * the person stored. A refused create aborts the paused request with nothing
116
+ * sent. A gated recognizer never sits in BUILTIN_REGISTRY, so it is paused only
117
+ * after a sync.
118
+ * `payrails_device_encrypt`: Payrails' card save and card-form payment, which
119
+ * this build pauses only once it has bound the request to a captured session
120
+ * (payrails.ts). A gated
118
121
  * recognizer never sits in BUILTIN_REGISTRY, so it is paused only after a sync.
119
122
  * `converge_hpp_process`: Elavon Converge's Hosted Payment Page card request
120
123
  * (elavon-converge.ts), paused in token mode and judged by the pre-claim gate.
@@ -166,8 +169,24 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
166
169
  * finds a card in it (cybersource-secure-acceptance.ts). Served on the same terms,
167
170
  * so every other company keeps the stop every build applies to a card posted to
168
171
  * Secure Acceptance.
172
+ * `gravy_session_fields_put`: Gravy Secure Fields' update of a checkout session,
173
+ * the one card request a recognizer declares as a PUT. This build pauses that PUT
174
+ * from Gravy's controller frame as it pauses a POST (isRecognizerRequest), creates
175
+ * the authorization with the PUT, and answers the frame with Gravy's own answer to
176
+ * the cardholder's device. Served on the same terms; an older build never sees the
177
+ * entry, and every company Agentcard has not turned Gravy on for keeps today's path,
178
+ * where the request continues to Gravy untouched.
179
+ * `moneris_hosted_tokenization`: Moneris Hosted Tokenization's card request, the
180
+ * frame's form post to /HPPtoken/request.php. This build pauses it only when it
181
+ * carries the number, the expiry and the CVD the cardholder's device fills, fails a
182
+ * frame that leaves the expiry or CVD to the merchant's page in the browser with a
183
+ * `blocked` event, `request_without_card`, and answers with Moneris's token as the
184
+ * API recorded it. The device sends the card through the checkout relay. Served on
185
+ * the same terms: only to a build that lists it, for a company Agentcard turned
186
+ * Moneris on for. A gated recognizer never sits in BUILTIN_REGISTRY, so it is paused
187
+ * only after a sync.
169
188
  */
170
- export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CYBERSOURCE_FLEX_CAPABILITY, JUSPAY_CAPABILITY, DATATRANS_CAPABILITY, 'authorize_net_dpm_form', PELECARD_CAPABILITY, ACI_CAPABILITY, 'creditguard_pps_process', PRIMER_CAPABILITY, PAYRAILS_CAPABILITY, CONVERGE_CAPABILITY, EPROTECT_CAPABILITY, WSPAY_CAPABILITY, SHIJI_STS_CAPABILITY, AMADEUS_CHECKOUT_CAPABILITY, 'worldline_mycheckout_form', 'verifone_card_capture', 'ekashu_hosted_payment_page', SECURE_ACCEPTANCE_CAPABILITY];
189
+ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CYBERSOURCE_FLEX_CAPABILITY, JUSPAY_CAPABILITY, DATATRANS_CAPABILITY, 'authorize_net_dpm_form', PELECARD_CAPABILITY, ACI_CAPABILITY, 'creditguard_pps_process', PRIMER_CAPABILITY, PAYRAILS_CAPABILITY, CONVERGE_CAPABILITY, EPROTECT_CAPABILITY, WSPAY_CAPABILITY, SHIJI_STS_CAPABILITY, AMADEUS_CHECKOUT_CAPABILITY, 'worldline_mycheckout_form', 'verifone_card_capture', 'ekashu_hosted_payment_page', SECURE_ACCEPTANCE_CAPABILITY, 'gravy_session_fields_put', 'moneris_hosted_tokenization'];
171
190
  /**
172
191
  * Processors whose paused request names no amount at all, so the pair the
173
192
  * agent passes is the amount the cardholder approves: authorize() refuses one
@@ -185,12 +204,16 @@ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CY
185
204
  * it creates a token and charges nothing, and the merchant's server charges its
186
205
  * own cart total later, so the agent's pair, which the prepared checkout already
187
206
  * carries, is the total the cardholder approves, and the card that pays can spend
188
- * no more than that (the API's card rule).
207
+ * no more than that (the API's card rule). Moneris Hosted Tokenization's
208
+ * request.php carries the card and no price: the merchant's server charges the
209
+ * token later, so the agent's pair, above zero (MONERIS_PSP below), is the one
210
+ * figure the approval shows.
189
211
  */
190
- const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP];
212
+ const MONERIS_PSP = 'moneris';
213
+ const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP, MONERIS_PSP];
191
214
  /** How AmountRequiredError names a processor. */
192
215
  const PROCESSOR_NAMES = { [GMO_PSP]: 'GMO', [PELECARD_PSP]: 'Pelecard', [WSPAY_PSP]: 'WSPay',
193
- [SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance' };
216
+ [SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris' };
194
217
  /**
195
218
  * Processors whose request and answer name no amount at all, so the total the
196
219
  * payment page shows (`pageAmount`) is the one figure that ties the agent's pair
@@ -1162,8 +1185,9 @@ export class VaultClient {
1162
1185
  }
1163
1186
  /**
1164
1187
  * The recogniser that claims a card request, or null; what a paused request names as
1165
- * `recognizer`. A POST to a recognised endpoint, or for a recognizer whose card request is a
1166
- * GET (Worldpay eProtect) that exact GET, query included.
1188
+ * `recognizer`. A POST to a recognised endpoint, a PUT for a recognizer whose card request is
1189
+ * a PUT (Gravy), or for a recognizer whose card request is a GET (Worldpay eProtect) that
1190
+ * exact GET, query included.
1167
1191
  */
1168
1192
  recognizerOf(url, method = 'POST') {
1169
1193
  const rec = findRecognizer(url, this.mergedRegistry(), { sandbox: this.sandbox });
@@ -1189,7 +1213,8 @@ export class VaultClient {
1189
1213
  // payrails_device_encrypt, converge_hpp_process, worldpay_eprotect_jsonp,
1190
1214
  // wspay_confirm, shiji_sts_pinned_key, amadeus_checkout_actions.v1,
1191
1215
  // worldline_mycheckout_form, verifone_card_capture, ekashu_hosted_payment_page,
1192
- // cybersource_sa_token_create) and
1216
+ // cybersource_sa_token_create, gravy_session_fields_put,
1217
+ // moneris_hosted_tokenization) and
1193
1218
  // the caller's company is one Agentcard turned that processor on for, so this
1194
1219
  // build arms Fiserv's card capture, GMO's getToken, CyberSource Flex's card
1195
1220
  // fields, Juspay's card flow, Datatrans's Secure Fields card post, the
@@ -1197,8 +1222,9 @@ export class VaultClient {
1197
1222
  // CreditGuard's hosted page submit, Primer's card tokenization, Payrails' card
1198
1223
  // save, Converge's payment page, Worldpay eProtect's registration, WSPay's
1199
1224
  // card confirm, Shiji STS's card leg, Amadeus Checkout's card add,
1200
- // Worldline MyCheckout's card form and CyberSource Secure Acceptance's token
1201
- // create only for
1225
+ // Worldline MyCheckout's card form, CyberSource Secure Acceptance's token
1226
+ // create, Gravy's session fields PUT and Moneris Hosted
1227
+ // Tokenization's card request only for
1202
1228
  // such a company, and an older build never receives a recognizer it cannot
1203
1229
  // judge. Every other org's registry never recognizes a Flex, Juspay, Datatrans,
1204
1230
  // Pelecard, ACI, CreditGuard, Primer, Payrails, Converge, eProtect, WSPay, Shiji STS, Amadeus or
@@ -1293,8 +1319,9 @@ export class VaultClient {
1293
1319
  }
1294
1320
  /**
1295
1321
  * True when this request is a card tokenization we can take over: a POST to
1296
- * a recognized endpoint, or for a recognizer whose card request is a GET
1297
- * (Worldpay eProtect) that exact GET, query included.
1322
+ * a recognized endpoint, a PUT for a recognizer whose card request is a PUT
1323
+ * (Gravy), or for a recognizer whose card request is a GET (Worldpay eProtect)
1324
+ * that exact GET, query included.
1298
1325
  */
1299
1326
  isCardRequest(url, method = 'POST') {
1300
1327
  return this.recognizerOf(url, method) !== null;
@@ -1474,6 +1501,12 @@ export class VaultClient {
1474
1501
  throw fail('secure_acceptance_profile_id_invalid');
1475
1502
  if (secureAcceptance && !input.cardId)
1476
1503
  throw fail('card_required');
1504
+ // Amadeus Checkout: Air France and KLM keep the expiry in their own form, where the agent types the
1505
+ // paying card's real expiry (placeholderCard), so the preparation names that card. The API refuses
1506
+ // one without it and approves no other card; refusing here asks nobody to approve it.
1507
+ const amadeus = input.psp === AMADEUS_CHECKOUT_PSP;
1508
+ if (amadeus && !input.cardId)
1509
+ throw fail('card_required');
1477
1510
  // CyberSource Flex, tokenized before Pay: the loaded card field's capture context and fields,
1478
1511
  // verified here against the keys payment-core pins before anything is created (the API and the
1479
1512
  // cardholder's device verify them again).
@@ -1596,6 +1629,8 @@ export class VaultClient {
1596
1629
  || (eprotect && (state.paypage_id !== input.paypageId || state.card_id !== input.cardId))
1597
1630
  // Secure Acceptance: the merchant profile and the card the cardholder approved are the ones asked for.
1598
1631
  || (secureAcceptance && (state.secure_acceptance_profile_id !== secureAcceptanceProfileId || state.card_id !== input.cardId))
1632
+ // Amadeus: the card the cardholder approved is the one whose expiry the agent typed.
1633
+ || (amadeus && state.card_id !== input.cardId)
1599
1634
  // The API says a preparation tokenizes before Pay exactly when this one carried a capture context.
1600
1635
  || (state.tokenize_before_pay === true) !== !!flexContext)
1601
1636
  throw fail('ready_unconfirmed', id);
@@ -1863,7 +1898,12 @@ export class VaultClient {
1863
1898
  // payrails_session_key_required.
1864
1899
  const sidecar = input.request.payrails;
1865
1900
  if (mode === 'device_encrypt' && (!sidecar || typeof sidecar.encryption_public_key !== 'string' || !sidecar.encryption_public_key)) {
1866
- throw new Error('A Payrails card save needs request.payrails.encryption_public_key, the session key from the checkout\'s Payrails init payload (the adapters capture it). Nothing was created.');
1901
+ throw new Error('A Payrails card save or card-form payment needs request.payrails.encryption_public_key, the session key from the checkout\'s Payrails init payload (the adapters capture it). Nothing was created.');
1902
+ }
1903
+ // A card-form payment's ciphertext carries the session's holderReference, which its body does not.
1904
+ const payrailsPayment = mode === 'device_encrypt' && isPayrailsPaymentUrl(input.request.url);
1905
+ if (payrailsPayment && (typeof sidecar?.holder_reference !== 'string' || !sidecar.holder_reference)) {
1906
+ throw new Error('A Payrails card-form payment needs request.payrails.holder_reference, the holderReference from the checkout\'s Payrails init payload (the adapters capture it). Nothing was created.');
1867
1907
  }
1868
1908
  // A preparation that tokenized before Pay pays only a field request loaded under the capture
1869
1909
  // context and fields its cardholder approved: the device holds CyberSource's token for that context.
@@ -1871,20 +1911,23 @@ export class VaultClient {
1871
1911
  throw new CheckoutPreparationError(preparation.id, 'checkout_changed');
1872
1912
  }
1873
1913
  // Say no rather than coerce. Each recognizer's card request has exactly one
1874
- // method (recognizerRequestMethod): a POST body, or for Worldpay eProtect the
1875
- // GET whose query carries the card. The service stores the replay template
1876
- // with that method, so a caller handing in another one would get it
1877
- // silently rewritten and the cardholder's device would replay something the
1878
- // caller never asked for. A direct caller deserves to be told, not surprised.
1879
- // A card endpoint has no recognizer: its card request is its profile's own method (a POST, or
1880
- // Target Optical's PUT), which admitCardEndpoint already held the request to.
1914
+ // method (recognizerRequestMethod): a POST body, Gravy's PUT body, or for
1915
+ // Worldpay eProtect the GET whose query carries the card. The service stores
1916
+ // the replay template with that method, so a caller handing in another one
1917
+ // would get it silently rewritten and the cardholder's device would replay
1918
+ // something the caller never asked for. A direct caller deserves to be told,
1919
+ // not surprised. A card endpoint has no recognizer: its card request is its
1920
+ // profile's own method (a POST, or Target Optical's PUT), which
1921
+ // admitCardEndpoint already held the request to.
1881
1922
  const method = (input.request.method ?? cardEndpoint?.method ?? 'POST').toUpperCase();
1882
1923
  const cardMethod = rec ? recognizerRequestMethod(rec) : cardEndpoint ? cardEndpoint.method : 'POST';
1883
1924
  if (method !== cardMethod) {
1884
1925
  throw new Error(cardMethod === 'GET'
1885
1926
  ? `a ${rec?.psp} card registration is a GET; got ${method} for ${redactUrl(input.request.url)}.`
1886
- : `checkout authorization is POST-only; got ${method} for ${redactUrl(input.request.url)}. ` +
1887
- 'A non-POST tokenizer needs recognizer support before it can be intercepted.');
1927
+ : cardMethod === 'PUT' && rec
1928
+ ? `a ${rec.psp} card request is a PUT; got ${method} for ${redactUrl(input.request.url)}.`
1929
+ : `checkout authorization is POST-only; got ${method} for ${redactUrl(input.request.url)}. ` +
1930
+ 'A non-POST tokenizer needs recognizer support before it can be intercepted.');
1888
1931
  }
1889
1932
  // A GET card request is its URL alone. This build completes one: Worldpay
1890
1933
  // eProtect's registration exactly as payment-core admits it, with no body.
@@ -1915,6 +1958,10 @@ export class VaultClient {
1915
1958
  // amount_required.
1916
1959
  if (!hasAmount && rec && AGENT_AMOUNT_PROCESSORS.includes(rec.psp))
1917
1960
  throw new AmountRequiredError(rec.psp);
1961
+ // A Moneris token is charged later for whatever the merchant's server decides, so a zero pair
1962
+ // would show the cardholder no price at all: it is refused like a missing one.
1963
+ if (hasAmount && rec && rec.psp === MONERIS_PSP && Number(input.amount) <= 0)
1964
+ throw new AmountRequiredError(rec.psp);
1918
1965
  // Nor is the agent's pair tied to the page by anything but the total the
1919
1966
  // page shows: without it the cardholder could approve one figure while the
1920
1967
  // page charges another. The API refuses the same create as page_amount_required.
@@ -1924,7 +1971,8 @@ export class VaultClient {
1924
1971
  // later, under another session), so the price the cardholder approves is
1925
1972
  // the one sent here: the agent's pair or else the page total. Refused
1926
1973
  // before any create or prompt, the way the API refuses amount_required.
1927
- if (mode === 'device_encrypt' && !hasAmount && !input.pageAmount) {
1974
+ // A card-form payment names the amount it authorizes, which the API reads.
1975
+ if (mode === 'device_encrypt' && !payrailsPayment && !hasAmount && !input.pageAmount) {
1928
1976
  throw new Error('A Payrails card save names no amount, so pass amount and currency (or let the adapter read the page total): that is the amount the cardholder approves. Nothing was created and nothing was charged.');
1929
1977
  }
1930
1978
  const timeoutMs = input.timeoutMs ?? 15 * 60_000;
@@ -1996,8 +2044,10 @@ export class VaultClient {
1996
2044
  microform: { version: input.request.microform.version, fields: [...input.request.microform.fields],
1997
2045
  ...(input.request.microform.trigger ? { trigger: input.request.microform.trigger } : {}) },
1998
2046
  } : {}),
1999
- // Only the key: the token already rides in the passthrough authorization header.
2000
- ...(mode === 'device_encrypt' && sidecar ? { payrails: { encryption_public_key: sidecar.encryption_public_key } } : {}),
2047
+ // Only the key, and a card-form payment's holderReference: the token already rides in the
2048
+ // passthrough authorization header.
2049
+ ...(mode === 'device_encrypt' && sidecar ? { payrails: { encryption_public_key: sidecar.encryption_public_key,
2050
+ ...(payrailsPayment ? { holder_reference: sidecar.holder_reference } : {}) } } : {}),
2001
2051
  },
2002
2052
  };
2003
2053
  try {
@@ -2063,7 +2113,13 @@ export class VaultClient {
2063
2113
  // then at the caller's interval; at the default 2 seconds the first read alone would miss it.
2064
2114
  // The API's bind names 100 ms as such a row's poll interval, so slow_down admits these reads
2065
2115
  // (as an eProtect row names the 500 ms read above).
2066
- const preparedFlexPollUntil = preparation?.cybersourceFlex ? Date.now() + 10_000 : 0;
2116
+ // A prepared Bambora token create too: Custom Checkout's card frame gives its tokenization
2117
+ // request 5 seconds from Pay, and the cardholder's device answers a prepared token 1.5 to 4
2118
+ // seconds after this bind. Read every 2 seconds, an answer later than the first read waited
2119
+ // for the read 4 seconds after the bind, at or past the frame's timer; read every 100 ms, it
2120
+ // reaches the frame within about 0.2 seconds of the device's answer. The API's bind names
2121
+ // 100 ms on such a row too.
2122
+ const preparedTightPollUntil = preparation?.cybersourceFlex || preparation?.psp === 'bambora' ? Date.now() + 10_000 : 0;
2067
2123
  let execution = {};
2068
2124
  let approvalDelivered = false;
2069
2125
  const deliverApproval = (state) => {
@@ -2112,7 +2168,7 @@ export class VaultClient {
2112
2168
  if (stopSignal?.aborted)
2113
2169
  throw new PaymentOutcomeUnknownError(authorizationId, input.merchantSignal?.aborted ? 'merchant_request_aborted' : 'local_cancel');
2114
2170
  const pollInterval = Date.now() < preparedFastPollUntil ? Math.min(this.pollIntervalMs, 500)
2115
- : Date.now() < preparedFlexPollUntil ? Math.min(this.pollIntervalMs, 100) : this.pollIntervalMs;
2171
+ : Date.now() < preparedTightPollUntil ? Math.min(this.pollIntervalMs, 100) : this.pollIntervalMs;
2116
2172
  // A Secure Acceptance read also wakes when its reply window closes (Infinity for every other processor).
2117
2173
  await interruptibleSleep(Math.min(pollInterval, Math.max(0, deadline - Date.now()), Math.max(0, secureAcceptanceReplyBy - Date.now())), stopSignal);
2118
2174
  if (stopSignal?.aborted)
@@ -2247,16 +2303,17 @@ export class VaultClient {
2247
2303
  fields: { ...sub.fields },
2248
2304
  ...(removeRaw ? { remove: [...removeRaw] } : {}),
2249
2305
  },
2250
- ...(shiji ? { shijiStsCompanion: Object.freeze({ keySequences: Object.freeze([...s.shiji_sts_companion.key_sequences]) }) } : {}),
2306
+ ...(shiji ? { shijiStsCompanion: Object.freeze({ keySequenceSha256: Object.freeze([...s.shiji_sts_companion.key_sequence_sha256]) }) } : {}),
2251
2307
  ...amountAuthority,
2252
2308
  ...execution,
2253
2309
  };
2254
2310
  }
2255
2311
  if (approvedMode === 'device_encrypt') {
2256
2312
  // The device sent the card to Payrails itself; this is Payrails' answer to it. It
2257
- // enters the page only as a 201 for a card instrument, rebuilt from payment-core's
2258
- // allow-list under a JSON content type (payrails.ts payrailsSaveAnswer). Anything else
2259
- // is never handed over: the card may be saved, so the outcome is unknown, not declined.
2313
+ // enters the page only as a 201 for a card instrument or, for a card-form payment, a 2xx
2314
+ // naming the authorize action, rebuilt from payment-core's allow-list under a JSON
2315
+ // content type (payrails.ts payrailsAnswer, by the paused URL). Anything else is never
2316
+ // handed over: the card may be saved or paying, so the outcome is unknown, not declined.
2260
2317
  // Autopilot never runs this mode, so an autopilot answer is not one to act on either.
2261
2318
  if (execution.executionMode === 'autopilot')
2262
2319
  throw new PaymentOutcomeUnknownError(authorizationId, 'autopilot_submission_mode_invalid');
@@ -2264,7 +2321,7 @@ export class VaultClient {
2264
2321
  throw new PaymentOutcomeUnknownError(authorizationId, 'approved_mode_unsupported');
2265
2322
  const saved = s.response;
2266
2323
  const answer = saved && typeof saved === 'object' && Number.isInteger(saved.status) && typeof saved.body === 'string'
2267
- ? payrailsSaveAnswer(saved.status, saved.body) : null;
2324
+ ? payrailsAnswer(saved.status, saved.body, input.request.url) : null;
2268
2325
  if (!answer)
2269
2326
  throw new PaymentOutcomeUnknownError(authorizationId, 'payrails_answer_unconfirmed');
2270
2327
  if (s.processor_context !== undefined)
@@ -54,7 +54,7 @@ declare function parseCreditguardTransaction(body: any, txId: any): {
54
54
  personalIdAlwaysEnabled: boolean;
55
55
  inputs: any;
56
56
  } | null;
57
- declare function creditguardTransactionRefusal(txn: any, expectation: any): "otp" | "keep_on_file" | "dcc" | "installments" | "personal_id" | "jwe_unsupported" | "transaction_type" | "amount_mismatch" | "environment_mismatch" | "currency_mismatch" | "transaction_unreadable" | "three_d_secure" | "form_inputs" | "card_field_hidden" | "no_retries_left" | "jwe_public_key_malformed" | null;
57
+ declare function creditguardTransactionRefusal(txn: any, expectation: any): "otp" | "keep_on_file" | "dcc" | "installments" | "personal_id" | "jwe_unsupported" | "transaction_type" | "amount_mismatch" | "environment_mismatch" | "currency_mismatch" | "transaction_unreadable" | "three_d_secure" | "form_inputs" | "card_field_hidden" | "jwe_public_key_malformed" | null;
58
58
  declare function creditguardSendWindowRefusal(timing: any): "timing_unknown" | "page_expired" | "recaptcha_expired" | null;
59
59
  declare var CREDITGUARD_REFUSAL_CODES: readonly string[];
60
60
  declare function creditguardResponseOutcome(status: any, body: any, options: any): {
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 83caafdf10afb4617e5eb3a896d3a1ba4b5c098747495658529c5d13798051cc
3
+ // artifact-sha256: 58593275ccbce7e76a1aa68065eb63063cdf0ed00d533706bec557cb8a21cbc8
4
4
  // src/creditguard.js
5
5
  var CREDITGUARD_PPS_HOSTS = Object.freeze(["pps.creditguard.co.il", "pps2.creditguard.co.il", "ppsuat.creditguard.co.il"]);
6
6
  var CREDITGUARD_SANDBOX_HOST = "ppsuat.creditguard.co.il";
@@ -572,8 +572,6 @@ function creditguardTransactionRefusal(txn, expectation) {
572
572
  const form = formInputsRefusal(txn.inputs);
573
573
  if (form)
574
574
  return form;
575
- if (txn.remainingSubmitRetries === null || txn.remainingSubmitRetries === 0)
576
- return "no_retries_left";
577
575
  const environment = creditguardPreparationEnvironment(expectation.hostname);
578
576
  if (environment === null || environment === "sandbox" !== (txn.envType === "test") || typeof expectation.sandbox !== "boolean" || expectation.sandbox !== (environment === "sandbox"))
579
577
  return "environment_mismatch";
@@ -13,12 +13,13 @@ import type { PreparedCheckout, ReplayResponse } from './client.js';
13
13
  * always a prepared one (authorize() requires it), so its preparation names
14
14
  * the processor and the key pin the cardholder approved. It continues only a
15
15
  * request on Fiserv's capture hosts, and only when that capture's own pin (its
16
- * envelope's key, pinned for its endpoint and its merchant) is the approved
17
- * pin; then Fiserv's own substitution writes only the envelope's four members
18
- * at source.encryptionData of the live paused body, and throws for a body that
19
- * is not the capture Agentcard covers or an envelope under another key than
20
- * the one the paused capture names (fiserv.ts). Any other approval never meets
21
- * a Fiserv capture host. Every refusal throws before anything is sent.
16
+ * envelope's key, or for a credentials session's key its merchant's, pinned for
17
+ * its endpoint and its merchant) is the approved pin; then Fiserv's own
18
+ * substitution writes only the envelope's four members at source.encryptionData
19
+ * of the live paused body, and throws for a body that is not the capture
20
+ * Agentcard covers or an envelope under another key than that pin's
21
+ * (fiserv.ts). Any other approval never meets a Fiserv capture host. Every
22
+ * refusal throws before anything is sent.
22
23
  */
23
24
  export declare function cseBody(body: string, replay: Extract<ReplayResponse, {
24
25
  mode: 'cse';
package/dist/cse-body.js CHANGED
@@ -18,12 +18,13 @@ import { substituteVerifoneBody } from './verifone.js';
18
18
  * always a prepared one (authorize() requires it), so its preparation names
19
19
  * the processor and the key pin the cardholder approved. It continues only a
20
20
  * request on Fiserv's capture hosts, and only when that capture's own pin (its
21
- * envelope's key, pinned for its endpoint and its merchant) is the approved
22
- * pin; then Fiserv's own substitution writes only the envelope's four members
23
- * at source.encryptionData of the live paused body, and throws for a body that
24
- * is not the capture Agentcard covers or an envelope under another key than
25
- * the one the paused capture names (fiserv.ts). Any other approval never meets
26
- * a Fiserv capture host. Every refusal throws before anything is sent.
21
+ * envelope's key, or for a credentials session's key its merchant's, pinned for
22
+ * its endpoint and its merchant) is the approved pin; then Fiserv's own
23
+ * substitution writes only the envelope's four members at source.encryptionData
24
+ * of the live paused body, and throws for a body that is not the capture
25
+ * Agentcard covers or an envelope under another key than that pin's
26
+ * (fiserv.ts). Any other approval never meets a Fiserv capture host. Every
27
+ * refusal throws before anything is sent.
27
28
  */
28
29
  export function cseBody(body, replay, url, preparation) {
29
30
  // A Verifone approval is always a prepared one for the profile it pays, and continues only the
@@ -39,7 +40,7 @@ export function cseBody(body, replay, url, preparation) {
39
40
  if (replay.kind !== undefined || !isFiservCaptureHost(url) || fiservCapturePinId(url, body) !== preparation.merchantProfile) {
40
41
  throw new Error('Refusing to substitute: the paused request is not a Fiserv capture under the key pin the cardholder approved.');
41
42
  }
42
- return substituteFiservEnvelope(body, replay.substitutions);
43
+ return substituteFiservEnvelope(body, replay.substitutions, url);
43
44
  }
44
45
  if (isFiservCaptureHost(url))
45
46
  throw new Error('Refusing to substitute: a Fiserv capture continues only through a prepared Fiserv approval.');
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 0179250ba6f44c33967a08dc4ce3a891d8b73f0f7eb60e9cab34f801dc2a4c57
3
+ // artifact-sha256: fdee611015d42dc0a679e93a64766ac971b190fcc8f17a107d761c414569e5f9
4
4
  // src/datatrans.js
5
5
  var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
6
6
  var DATATRANS_TOKENIZE_PATH = "/upp/payment/SecureFields/paymentField";
@@ -178,15 +178,18 @@ function judgeBody(body) {
178
178
  if (!pairs)
179
179
  return null;
180
180
  const fields = new Map(pairs.map(({ key, value }) => [key, value]));
181
+ const merchantHeldExpiry = !fields.get("expm") && !fields.get("expy") && fields.has("expm") === fields.has("expy") && fields.get("usage") !== "REGISTRATION";
181
182
  for (const [key, value] of fields) {
182
183
  if (!KEYS.has(key))
183
184
  return null;
185
+ if (merchantHeldExpiry && (key === "expm" || key === "expy"))
186
+ continue;
184
187
  if (EMPTY_ONLY.has(key) ? value !== "" : !RULES[key](value))
185
188
  return null;
186
189
  }
187
- if (!REQUIRED.every((key) => fields.has(key)))
190
+ if (!REQUIRED.every((key) => fields.has(key) || merchantHeldExpiry && (key === "expm" || key === "expy")))
188
191
  return null;
189
- return { pairs, fields, usage: fields.get("usage") ?? "" };
192
+ return { pairs, fields, usage: fields.get("usage") ?? "", merchantHeldExpiry };
190
193
  }
191
194
  function datatransRegistrationRefusal(usage, card, policy = DATATRANS_REGISTRATION_POLICY) {
192
195
  if (usage !== "REGISTRATION")
@@ -319,14 +322,14 @@ function injectDatatransCard(body, card, policy = DATATRANS_REGISTRATION_POLICY)
319
322
  if (!fields.get("cvv") || !digits(card.cvc, 3, 4))
320
323
  throw new Error(FILL_REFUSAL);
321
324
  const yy = String(year % 100).padStart(2, "0");
322
- const values = {
325
+ const values = judged.merchantHeldExpiry ? { cardNumber: card.number, cvv: card.cvc } : {
323
326
  cardNumber: card.number,
324
327
  cvv: card.cvc,
325
328
  expm: fields.get("expm").length === 2 ? String(month).padStart(2, "0") : String(month),
326
329
  expy: fields.get("expy").length === 4 ? `20${yy}` : yy
327
330
  };
328
331
  const written = judged.pairs.map((pair) => owns(values, pair.key) ? `${pair.rawKey}=${encodeDatatransFormValue(values[pair.key])}` : `${pair.rawKey}=${pair.raw}`);
329
- return { body: written.join("&"), where: ["cardNumber", "cvv", "expm", "expy"] };
332
+ return { body: written.join("&"), where: Object.keys(values) };
330
333
  }
331
334
  var TRANSACTION_ID = /^[0-9]{18}$/;
332
335
  var CARD_WORD = /^[A-Za-z][A-Za-z _-]{0,31}$/;
@@ -20,7 +20,7 @@ export declare const CONVERGE_CAPABILITY = "converge_hpp_process";
20
20
  */
21
21
  export declare const CONVERGE_REFUSAL_REASONS: readonly ["converge_body_malformed", "converge_payment_type_refused", "converge_debit_card_refused", "converge_push_to_card_refused", "converge_gift_card_refused", "converge_credential_refused", "converge_wallet_refused", "converge_captcha_refused", "converge_service_fee_refused", "converge_3ds_follow_up_refused", "converge_surcharge_refused", "converge_amount_add_on_refused", "converge_card_saving_refused", "converge_recurring_refused", "converge_currency_refused", "converge_amount_missing", "converge_context_missing", "converge_card_missing", "converge_card_malformed", "converge_url_refused", "converge_method_refused", "converge_content_type_refused"];
22
22
  export type ConvergeRefusalReason = typeof CONVERGE_REFUSAL_REASONS[number];
23
- /** True when the URL's host is one of Converge's two payment page hosts. */
23
+ /** True when the URL's host is one of Converge's three payment page hosts: api, www and the demo. */
24
24
  export declare function isConvergeHost(url: string): boolean;
25
25
  /**
26
26
  * The pause decision for a card-carrying POST the registry recognized on a Converge host. Null
@@ -1,13 +1,14 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: dc4269c2533c43ddcc4f7be0f3a4645beea09bce6854c98e38701f29cf037e2b
3
+ // artifact-sha256: 009a8b902de51c4dadddae592b32d2edbd5b394f130938e1a41cd62a06a234a8
4
4
  // src/elavon-converge.js
5
- var CONVERGE_HOSTS = /* @__PURE__ */ Object.freeze(["api.convergepay.com", "api.demo.convergepay.com"]);
5
+ var CONVERGE_HOSTS = /* @__PURE__ */ Object.freeze(["api.convergepay.com", "api.demo.convergepay.com", "www.convergepay.com"]);
6
6
  var CONVERGE_DEMO_HOST = "api.demo.convergepay.com";
7
7
  var CONVERGE_PROCESS_PATH = "/hosted-payments/service/payment/hpp/process";
8
8
  var CONVERGE_PROCESS_URLS = /* @__PURE__ */ Object.freeze([
9
9
  "https://api.convergepay.com/hosted-payments/service/payment/hpp/process",
10
- "https://api.demo.convergepay.com/hosted-payments/service/payment/hpp/process"
10
+ "https://api.demo.convergepay.com/hosted-payments/service/payment/hpp/process",
11
+ "https://www.convergepay.com/hosted-payments/service/payment/hpp/process"
11
12
  ]);
12
13
  var CONVERGE_REFUSAL_CODES = /* @__PURE__ */ Object.freeze([
13
14
  "converge_body_malformed",
@@ -72,6 +73,7 @@ var RECURRING_FIELDS = /* @__PURE__ */ Object.freeze([
72
73
  "ssl_recurring_batch_count",
73
74
  "ssl_installment_id"
74
75
  ]);
76
+ var ONE_TIME_RECURRING_FLAG = "false";
75
77
  var CARD_SAVING_FLAGS = /* @__PURE__ */ Object.freeze(["ssl_get_token", "ssl_add_token"]);
76
78
  var CREDENTIAL_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_account_id", "ssl_merchant_id", "ssl_user_id", "ssl_pin", "ssl_vendor_id"]);
77
79
  var AMOUNT_ADD_ON_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_tip_amount", "ssl_cashback_amount"]);
@@ -81,6 +83,7 @@ var CVC = /^\d{3,4}$/;
81
83
  var AMOUNT = /^(\d{1,13})(?:\.(\d{1,2}))?$/;
82
84
  var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
83
85
  var owns = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
86
+ var recurringRequested = (data) => RECURRING_FIELDS.some((key) => owns(data, key) && !(key === "recurring" && data[key] === ONE_TIME_RECURRING_FLAG));
84
87
  var refuse = (code) => Object.freeze({ verdict: "refuse", code });
85
88
  var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
86
89
  var CONTINUE = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
@@ -142,7 +145,7 @@ function convergeBodyVerdict(body) {
142
145
  if (owns(data, "ssl_token") || CARD_SAVING_FLAGS.some((key) => owns(data, key) && !(typeof data[key] === "string" && /^n$/i.test(data[key])))) {
143
146
  return refuse("converge_card_saving_refused");
144
147
  }
145
- if (RECURRING_FIELDS.some((key) => owns(data, key)))
148
+ if (recurringRequested(data))
146
149
  return refuse("converge_recurring_refused");
147
150
  if (owns(data, "ssl_transaction_currency") && !(typeof data.ssl_transaction_currency === "string" && /^usd$/i.test(data.ssl_transaction_currency))) {
148
151
  return refuse("converge_currency_refused");
@@ -1,6 +1,7 @@
1
1
  // Elavon Converge Hosted Payment Page (psp `elavon_converge`): the page NY DMV's payment apps
2
- // redirect to, api.convergepay.com/hosted-payments/?ssl_txn_auth_token=<one-time token> (the
3
- // demo environment serves the same page on api.demo.convergepay.com). Converge's own AngularJS
2
+ // redirect to, api.convergepay.com/hosted-payments/?ssl_txn_auth_token=<one-time token>. Every
3
+ // Converge Buy Button and pay link opens the same page on www.convergepay.com, and the demo
4
+ // environment serves it on api.demo.convergepay.com. Converge's own AngularJS
4
5
  // app posts the card in one same-origin JSON XHR, POST /hosted-payments/service/payment/hpp/process,
5
6
  // with the card at paymentData.ssl_card_number, ssl_exp_date (MMYY) and ssl_cvv2cvc2, the amount
6
7
  // at paymentData.ssl_amount, and the page's rolling session in `context`. The same URL also takes
@@ -59,7 +60,7 @@ export const CONVERGE_REFUSAL_REASONS = [
59
60
  'converge_method_refused',
60
61
  'converge_content_type_refused',
61
62
  ];
62
- /** True when the URL's host is one of Converge's two payment page hosts. */
63
+ /** True when the URL's host is one of Converge's three payment page hosts: api, www and the demo. */
63
64
  export function isConvergeHost(url) {
64
65
  try {
65
66
  return CONVERGE_HOSTS.includes(new URL(url).hostname);
package/dist/fiserv.d.ts CHANGED
@@ -17,8 +17,9 @@ export declare function isFiservCaptureHost(url: string): boolean;
17
17
  /** The pinned key with this id, in either environment, or null. */
18
18
  export declare function fiservKeyPinById(id: unknown): FiservKeyPin | null;
19
19
  /**
20
- * The id of the pin a paused capture's card may be sealed under (its envelope's key,
21
- * pinned for its endpoint's environment and for the merchant its body names), or null.
20
+ * The id of the pin a paused capture's card may be sealed under (its envelope's key or,
21
+ * for a credentials session's key, the key pinned for the merchant its body names; for its
22
+ * endpoint's environment and that merchant), or null.
22
23
  */
23
24
  export declare function fiservCapturePinId(url: string, body: string | null): string | null;
24
25
  /** The card-capture endpoint a Fiserv preparation names for its environment. */
@@ -59,7 +60,10 @@ export declare function isFiservSubstitution(sub: unknown): boolean;
59
60
  * The paused Fiserv capture with the approval's envelope written over the four members
60
61
  * its source.encryptionData already carries, and every other byte the frame's own. It
61
62
  * throws, writing nothing, for a body that is not the capture Agentcard covers, for any
62
- * substitution but Fiserv's envelope, and for an envelope under another key than the one
63
- * the paused capture names. Run this on a Fiserv approval, never substituteEncryptedFields.
63
+ * substitution but Fiserv's envelope, and for an envelope under another key than the
64
+ * paused capture's card goes under: the key it names or, when it names a credentials
65
+ * session's key, the key pinned for its merchant on the endpoint `url` names (the paused
66
+ * capture's own URL, which a session's key requires), whose id then replaces the session's.
67
+ * Run this on a Fiserv approval, never substituteEncryptedFields.
64
68
  */
65
- export declare function substituteFiservEnvelope(body: string, sub: Substitutions): string;
69
+ export declare function substituteFiservEnvelope(body: string, sub: Substitutions, url?: string): string;
@@ -15,6 +15,7 @@ declare var FISERV_KEY_PINS: any;
15
15
  declare function fiservKeyPin(keyId: any, environment: any): any;
16
16
  declare function isFiservPinnedKeyId(keyId: any): any;
17
17
  declare function fiservKeyRefusal(keyId: any, environment: any, nowMs: any): "fiserv_key_unpinned" | "fiserv_key_inactive" | "fiserv_key_outside_validity" | null;
18
+ declare function fiservCheckoutHost(pinId: any, origin: any): string | null;
18
19
  declare function parseFiservPublishedKey(text2: any): {
19
20
  keyId: any;
20
21
  encryptionType: any;
@@ -38,7 +39,6 @@ declare function fiservErrorIdentifiers(text2: any): {
38
39
  declare function fiservCardCaptureRefusal(request: any): "fiserv_request_invalid" | "fiserv_endpoint_invalid" | "fiserv_body_invalid" | "fiserv_body_member_not_allowed" | "fiserv_source_not_encrypted_card" | "fiserv_envelope_invalid" | "fiserv_merchant_invalid" | "fiserv_transaction_details_invalid" | "fiserv_billing_address_invalid" | "fiserv_method_invalid" | "fiserv_headers_invalid" | "fiserv_header_not_allowed" | "fiserv_content_type_invalid" | "fiserv_auth_token_type_invalid" | "fiserv_merchant_header_mismatch" | "fiserv_terminal_header_mismatch" | "fiserv_header_value_invalid" | null;
39
40
  declare function isFiservCardCaptureRequest(request: any): boolean;
40
41
  declare function isFiservPausableBody(body: any): boolean;
41
- declare function fiservTemplateKeyId(body: any): any;
42
42
  declare function fiservCaptureMerchant(body: any): {
43
43
  merchantId: any;
44
44
  terminalId: any;
@@ -69,5 +69,5 @@ declare function fiservSubstitutions(envelope: any): {
69
69
  [k: string]: any;
70
70
  };
71
71
  };
72
- declare function substituteFiservEnvelope(body: any, sub: any): string;
73
- export { FISERV_CARD_CAPTURE_ENDPOINTS, FISERV_ENVELOPE_CONSTANTS, FISERV_KEY_PINS, FISERV_SIMULATOR_PANS, FISERV_SUBSTITUTION, encryptFiservCard, fiservApprovedEnvelopeRefusal, fiservCaptureCardMismatch, fiservCaptureKeyRefusal, fiservCaptureMerchant, fiservCapturePin, fiservCardCaptureRefusal, fiservEnvironment, fiservErrorIdentifiers, fiservKeyPin, fiservKeyRefusal, fiservPreparationUrl, fiservPublishedKeyRefusal, fiservSubstitutionFieldsRefusal, fiservSubstitutions, fiservTemplateKeyId, fiservTimestampMs, isFiservCardCaptureRequest, isFiservCardCaptureUrl, isFiservPausableBody, isFiservPinnedKeyId, isPreparedFiservRequest, parseFiservPublishedKey, sanitizeFiservCaptureResponse, substituteFiservEnvelope };
72
+ declare function substituteFiservEnvelope(body: any, sub: any, url?: null): string;
73
+ export { FISERV_CARD_CAPTURE_ENDPOINTS, FISERV_ENVELOPE_CONSTANTS, FISERV_KEY_PINS, FISERV_SIMULATOR_PANS, FISERV_SUBSTITUTION, encryptFiservCard, fiservApprovedEnvelopeRefusal, fiservCaptureCardMismatch, fiservCaptureKeyRefusal, fiservCaptureMerchant, fiservCapturePin, fiservCardCaptureRefusal, fiservCheckoutHost, fiservEnvironment, fiservErrorIdentifiers, fiservKeyPin, fiservKeyRefusal, fiservPreparationUrl, fiservPublishedKeyRefusal, fiservSubstitutionFieldsRefusal, fiservSubstitutions, fiservTimestampMs, isFiservCardCaptureRequest, isFiservCardCaptureUrl, isFiservPausableBody, isFiservPinnedKeyId, isPreparedFiservRequest, parseFiservPublishedKey, sanitizeFiservCaptureResponse, substituteFiservEnvelope };