paysafe-sdk 1.0.0

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/dist/index.js ADDED
@@ -0,0 +1,1548 @@
1
+ // src/core/errors.ts
2
+ var RETRYABLE_API_CODES = /* @__PURE__ */ new Set(["3028", "5000", "5001", "5002"]);
3
+ var RETRYABLE_HTTP_STATUSES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
4
+ var PaysafeError = class _PaysafeError extends Error {
5
+ kind;
6
+ code;
7
+ httpStatus;
8
+ fieldErrors;
9
+ details;
10
+ retryable;
11
+ constructor(init) {
12
+ super(formatMessage(init));
13
+ this.name = "PaysafeError";
14
+ this.kind = init.kind;
15
+ this.code = init.code;
16
+ this.httpStatus = init.httpStatus;
17
+ this.fieldErrors = init.fieldErrors ?? [];
18
+ this.details = init.details;
19
+ this.retryable = init.retryable ?? false;
20
+ if (init.cause !== void 0) {
21
+ this.cause = init.cause;
22
+ }
23
+ Object.setPrototypeOf(this, _PaysafeError.prototype);
24
+ }
25
+ /** Whether the SDK's retry policy should attempt this request again. */
26
+ isRetryable() {
27
+ return this.retryable;
28
+ }
29
+ static fromApiResponse(body, httpStatus) {
30
+ const errObj = isRecord(body.error) ? body.error : void 0;
31
+ const code = errObj ? stringify(errObj.code) : "";
32
+ let message = "Unknown API error";
33
+ if (errObj && typeof errObj.message === "string" && errObj.message !== "") {
34
+ message = errObj.message;
35
+ } else if (typeof body.message === "string" && body.message !== "") {
36
+ message = body.message;
37
+ }
38
+ let fieldErrors = [];
39
+ if (errObj && Array.isArray(errObj.fieldErrors)) {
40
+ fieldErrors = errObj.fieldErrors.filter(isRecord).map((fe) => ({ field: stringify(fe.field), error: stringify(fe.error) }));
41
+ }
42
+ return new _PaysafeError({
43
+ kind: "api_error",
44
+ code,
45
+ message,
46
+ httpStatus,
47
+ fieldErrors,
48
+ details: body,
49
+ retryable: RETRYABLE_API_CODES.has(code) || RETRYABLE_HTTP_STATUSES.has(httpStatus)
50
+ });
51
+ }
52
+ static httpError(cause, timedOut) {
53
+ if (timedOut) {
54
+ return new _PaysafeError({
55
+ kind: "timeout",
56
+ message: "Request timed out",
57
+ retryable: true,
58
+ cause
59
+ });
60
+ }
61
+ return new _PaysafeError({
62
+ kind: "http_error",
63
+ message: `HTTP transport error: ${describeCause(cause)}`,
64
+ retryable: false,
65
+ cause
66
+ });
67
+ }
68
+ static rateLimited() {
69
+ return new _PaysafeError({
70
+ kind: "rate_limited",
71
+ message: "Rate limit exceeded. Reduce request frequency.",
72
+ retryable: true
73
+ });
74
+ }
75
+ static invalidParams(message) {
76
+ return new _PaysafeError({ kind: "invalid_params", message, retryable: false });
77
+ }
78
+ static invalidConfig(message) {
79
+ return new _PaysafeError({ kind: "invalid_config", message, retryable: false });
80
+ }
81
+ static webhookMismatch() {
82
+ return new _PaysafeError({
83
+ kind: "webhook_signature_mismatch",
84
+ message: "Webhook HMAC-SHA256 signature does not match.",
85
+ retryable: false
86
+ });
87
+ }
88
+ static decodeError(cause) {
89
+ return new _PaysafeError({
90
+ kind: "decode_error",
91
+ message: `Failed to decode response: ${describeCause(cause)}`,
92
+ retryable: false,
93
+ cause
94
+ });
95
+ }
96
+ static contextCanceled(cause) {
97
+ return new _PaysafeError({
98
+ kind: "context_canceled",
99
+ message: `Request aborted: ${describeCause(cause)}`,
100
+ retryable: false,
101
+ cause
102
+ });
103
+ }
104
+ };
105
+ function formatMessage(init) {
106
+ return init.code ? `paysafe: ${init.kind} [${init.code}]: ${init.message}` : `paysafe: ${init.kind}: ${init.message}`;
107
+ }
108
+ function isRecord(value) {
109
+ return typeof value === "object" && value !== null && !Array.isArray(value);
110
+ }
111
+ function stringify(value) {
112
+ if (typeof value === "string") return value;
113
+ if (value === null || value === void 0) return "";
114
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
115
+ return String(value);
116
+ }
117
+ try {
118
+ return JSON.stringify(value) ?? "";
119
+ } catch {
120
+ return "";
121
+ }
122
+ }
123
+ function describeCause(cause) {
124
+ if (cause instanceof Error) return cause.message;
125
+ return String(cause);
126
+ }
127
+
128
+ // src/core/config.ts
129
+ var BASE_URLS = {
130
+ test: "https://api.test.paysafe.com",
131
+ production: "https://api.paysafe.com"
132
+ };
133
+ var PAYMENTS_PATH = "/paymenthub/v1";
134
+ var SCHEDULER_PATH = "/subscriptionsplans/v1";
135
+ var APPLICATIONS_PATH = "/merchant/v1";
136
+ var FX_RATES_PATH = "/fxrates/v1";
137
+ var BANK_ACCOUNT_VALIDATOR_PATH = "/bankaccountvalidator/v1";
138
+ var CUSTOMER_IDENTIFICATION_PATH = "/customeridentification/v1";
139
+ var ResolvedConfig = class {
140
+ username;
141
+ password;
142
+ environment;
143
+ accountId;
144
+ baseUrlOverride;
145
+ timeoutMs;
146
+ maxRetries;
147
+ retryBaseDelayMs;
148
+ rateLimit;
149
+ fetchImpl;
150
+ telemetryPrefix;
151
+ constructor(opts) {
152
+ this.username = opts.username;
153
+ this.password = opts.password;
154
+ this.environment = opts.environment ?? "test";
155
+ this.accountId = opts.accountId;
156
+ this.baseUrlOverride = opts.baseUrlOverride;
157
+ this.timeoutMs = opts.timeoutMs ?? 3e4;
158
+ this.maxRetries = opts.maxRetries ?? 3;
159
+ this.retryBaseDelayMs = opts.retryBaseDelayMs ?? 500;
160
+ this.rateLimit = opts.rateLimit ?? { limit: 100, windowMs: 1e3 };
161
+ this.telemetryPrefix = opts.telemetryPrefix ?? "paysafe";
162
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
163
+ if (typeof fetchImpl !== "function") {
164
+ throw PaysafeError.invalidConfig(
165
+ "No fetch implementation available. Provide one via `fetch` in PaysafeClientOptions (the global fetch is unavailable in this runtime)."
166
+ );
167
+ }
168
+ this.fetchImpl = fetchImpl.bind(globalThis);
169
+ this.validate();
170
+ }
171
+ validate() {
172
+ if (!this.username) {
173
+ throw PaysafeError.invalidConfig("username is required");
174
+ }
175
+ if (!this.password) {
176
+ throw PaysafeError.invalidConfig("password is required");
177
+ }
178
+ if (this.environment !== "test" && this.environment !== "production") {
179
+ throw PaysafeError.invalidConfig('environment must be "test" or "production"');
180
+ }
181
+ if (this.maxRetries < 0) {
182
+ throw PaysafeError.invalidConfig("maxRetries must be >= 0");
183
+ }
184
+ if (this.rateLimit.limit <= 0 || this.rateLimit.windowMs <= 0) {
185
+ throw PaysafeError.invalidConfig("rateLimit must have a positive limit and windowMs");
186
+ }
187
+ if (this.timeoutMs <= 0) {
188
+ throw PaysafeError.invalidConfig("timeoutMs must be > 0");
189
+ }
190
+ }
191
+ baseUrl() {
192
+ return this.baseUrlOverride ?? BASE_URLS[this.environment];
193
+ }
194
+ paymentsUrl() {
195
+ return this.baseUrl() + PAYMENTS_PATH;
196
+ }
197
+ schedulerUrl() {
198
+ return this.baseUrl() + SCHEDULER_PATH;
199
+ }
200
+ applicationsUrl() {
201
+ return this.baseUrl() + APPLICATIONS_PATH;
202
+ }
203
+ fxRatesUrl() {
204
+ return this.baseUrl() + FX_RATES_PATH;
205
+ }
206
+ bankAccountValidatorUrl() {
207
+ return this.baseUrl() + BANK_ACCOUNT_VALIDATOR_PATH;
208
+ }
209
+ customerIdentificationUrl() {
210
+ return this.baseUrl() + CUSTOMER_IDENTIFICATION_PATH;
211
+ }
212
+ /** Computes the Base64-encoded HTTP Basic Auth header value. */
213
+ authHeader() {
214
+ const raw = `${this.username}:${this.password}`;
215
+ return `Basic ${base64Encode(raw)}`;
216
+ }
217
+ /** Returns `override` if non-empty, otherwise the configured default account ID. */
218
+ resolveAccountId(override) {
219
+ if (override) return override;
220
+ if (this.accountId) return this.accountId;
221
+ throw PaysafeError.invalidParams(
222
+ "accountId is required: pass it explicitly or set a default via PaysafeClientOptions.accountId"
223
+ );
224
+ }
225
+ };
226
+ function base64Encode(raw) {
227
+ if (typeof btoa === "function") {
228
+ return btoa(raw);
229
+ }
230
+ return Buffer.from(raw, "utf-8").toString("base64");
231
+ }
232
+ function configFromEnv(overrides = {}) {
233
+ const env = typeof process !== "undefined" ? process.env : void 0;
234
+ if (!env) {
235
+ throw PaysafeError.invalidConfig(
236
+ "configFromEnv() requires a Node.js-like `process.env`; pass options explicitly in this runtime."
237
+ );
238
+ }
239
+ const base = {
240
+ username: env.PAYSAFE_USERNAME ?? "",
241
+ password: env.PAYSAFE_PASSWORD ?? ""
242
+ };
243
+ if (env.PAYSAFE_ENVIRONMENT === "production") {
244
+ base.environment = "production";
245
+ }
246
+ if (env.PAYSAFE_ACCOUNT_ID) {
247
+ base.accountId = env.PAYSAFE_ACCOUNT_ID;
248
+ }
249
+ return { ...base, ...overrides };
250
+ }
251
+
252
+ // src/core/telemetry.ts
253
+ function hasStatusCode(value) {
254
+ return typeof value === "object" && value !== null && "httpStatus" in value;
255
+ }
256
+ async function span(hook, meta, fn) {
257
+ const start = Date.now();
258
+ hook?.onStart?.(meta);
259
+ try {
260
+ const result = await fn();
261
+ hook?.onStop?.({
262
+ ...meta,
263
+ durationMs: Date.now() - start,
264
+ httpStatus: 0,
265
+ ok: true
266
+ });
267
+ return result;
268
+ } catch (error) {
269
+ const httpStatus = hasStatusCode(error) ? error.httpStatus ?? 0 : 0;
270
+ hook?.onStop?.({
271
+ ...meta,
272
+ durationMs: Date.now() - start,
273
+ httpStatus,
274
+ ok: false,
275
+ error
276
+ });
277
+ throw error;
278
+ }
279
+ }
280
+
281
+ // src/core/http-client.ts
282
+ var SDK_USER_AGENT = "paysafe-sdk/1.0.0 (+https://github.com/iamkanishka/paysafe-sdk)";
283
+ var MAX_JITTER_MS = 100;
284
+ function backoffDelayMs(baseMs, attempt) {
285
+ const multiplier = 2 ** attempt;
286
+ const jitter = Math.random() * MAX_JITTER_MS;
287
+ return baseMs * multiplier + jitter;
288
+ }
289
+ function sleep(ms, signal) {
290
+ return new Promise((resolve, reject) => {
291
+ const timer = setTimeout(resolve, ms);
292
+ signal?.addEventListener(
293
+ "abort",
294
+ () => {
295
+ clearTimeout(timer);
296
+ reject(PaysafeError.contextCanceled(signal.reason));
297
+ },
298
+ { once: true }
299
+ );
300
+ });
301
+ }
302
+ async function decodeErrorBody(response) {
303
+ const text = await response.text();
304
+ if (!text) return {};
305
+ try {
306
+ const parsed = JSON.parse(text);
307
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
308
+ return parsed;
309
+ }
310
+ return { message: text };
311
+ } catch {
312
+ return { message: text };
313
+ }
314
+ }
315
+ var HttpTransport = class {
316
+ constructor(cfg, limiter, hook) {
317
+ this.cfg = cfg;
318
+ this.limiter = limiter;
319
+ this.hook = hook;
320
+ }
321
+ cfg;
322
+ limiter;
323
+ hook;
324
+ /**
325
+ * Performs the HTTP round trip and returns the raw response body as
326
+ * text. Used directly for endpoints with no JSON object response body
327
+ * (e.g. `DELETE`).
328
+ */
329
+ async raw(options) {
330
+ const meta = {
331
+ prefix: this.cfg.telemetryPrefix,
332
+ api: options.api,
333
+ method: options.method,
334
+ path: options.url,
335
+ operation: options.operation
336
+ };
337
+ return span(this.hook, meta, async () => {
338
+ this.limiter.allow(this.cfg.username, this.cfg.rateLimit.limit, this.cfg.rateLimit.windowMs);
339
+ return this.doWithRetry(options, 0);
340
+ });
341
+ }
342
+ /**
343
+ * Performs the HTTP round trip and decodes the JSON response body as
344
+ * `T`. This is the common case used by nearly every resource method.
345
+ */
346
+ async do(options) {
347
+ const raw = await this.raw(options);
348
+ if (!raw) {
349
+ return {};
350
+ }
351
+ try {
352
+ return JSON.parse(raw);
353
+ } catch (cause) {
354
+ throw PaysafeError.decodeError(cause);
355
+ }
356
+ }
357
+ async doWithRetry(options, attempt) {
358
+ try {
359
+ return await this.doOnce(options);
360
+ } catch (err) {
361
+ const retryable = err instanceof PaysafeError && err.isRetryable();
362
+ if (retryable && attempt < this.cfg.maxRetries) {
363
+ const delay = backoffDelayMs(this.cfg.retryBaseDelayMs, attempt);
364
+ await sleep(delay, options.signal);
365
+ return this.doWithRetry(options, attempt + 1);
366
+ }
367
+ throw err;
368
+ }
369
+ }
370
+ async doOnce(options) {
371
+ const controller = new AbortController();
372
+ const timeoutTimer = setTimeout(
373
+ () => controller.abort(new Error("timeout")),
374
+ this.cfg.timeoutMs
375
+ );
376
+ if (options.signal) {
377
+ if (options.signal.aborted) {
378
+ controller.abort(options.signal.reason);
379
+ } else {
380
+ options.signal.addEventListener("abort", () => controller.abort(options.signal?.reason), {
381
+ once: true
382
+ });
383
+ }
384
+ }
385
+ const headers = {
386
+ Authorization: this.cfg.authHeader(),
387
+ Accept: "application/json",
388
+ "User-Agent": SDK_USER_AGENT
389
+ };
390
+ let requestBody;
391
+ if (options.body !== void 0) {
392
+ try {
393
+ requestBody = JSON.stringify(options.body);
394
+ } catch (cause) {
395
+ clearTimeout(timeoutTimer);
396
+ throw PaysafeError.invalidParams(`failed to encode request body: ${String(cause)}`);
397
+ }
398
+ headers["Content-Type"] = "application/json";
399
+ }
400
+ let response;
401
+ try {
402
+ response = await this.cfg.fetchImpl(options.url, {
403
+ method: options.method,
404
+ headers,
405
+ body: requestBody,
406
+ signal: controller.signal
407
+ });
408
+ } catch (cause) {
409
+ clearTimeout(timeoutTimer);
410
+ const timedOut = controller.signal.aborted;
411
+ throw PaysafeError.httpError(cause, timedOut);
412
+ }
413
+ clearTimeout(timeoutTimer);
414
+ if (response.ok) {
415
+ return response.text();
416
+ }
417
+ const errorBody = await decodeErrorBody(response);
418
+ throw PaysafeError.fromApiResponse(errorBody, response.status);
419
+ }
420
+ };
421
+
422
+ // src/core/rate-limiter.ts
423
+ function newBucket(limit, windowMs) {
424
+ return {
425
+ capacity: limit,
426
+ tokens: limit,
427
+ refillRatePerMs: limit / windowMs,
428
+ updatedAt: Date.now()
429
+ };
430
+ }
431
+ function tryConsume(bucket) {
432
+ const now = Date.now();
433
+ const elapsedMs = now - bucket.updatedAt;
434
+ bucket.updatedAt = now;
435
+ bucket.tokens = Math.min(bucket.capacity, bucket.tokens + elapsedMs * bucket.refillRatePerMs);
436
+ if (bucket.tokens >= 1) {
437
+ bucket.tokens -= 1;
438
+ return true;
439
+ }
440
+ return false;
441
+ }
442
+ var RateLimiter = class {
443
+ buckets = /* @__PURE__ */ new Map();
444
+ bucketFor(key, limit, windowMs) {
445
+ let bucket = this.buckets.get(key);
446
+ if (!bucket) {
447
+ bucket = newBucket(limit, windowMs);
448
+ this.buckets.set(key, bucket);
449
+ }
450
+ return bucket;
451
+ }
452
+ /**
453
+ * Checks (and, if permitted, consumes) one token for `key`. Throws a
454
+ * {@link PaysafeError} with `kind === "rate_limited"` if the bucket is
455
+ * exhausted.
456
+ */
457
+ allow(key, limit, windowMs) {
458
+ const window = windowMs > 0 ? windowMs : 1e3;
459
+ const bucket = this.bucketFor(key, limit, window);
460
+ if (!tryConsume(bucket)) {
461
+ throw PaysafeError.rateLimited();
462
+ }
463
+ }
464
+ };
465
+
466
+ // src/types/shared.ts
467
+ function findLinkByRel(links, rel) {
468
+ return links?.find((link) => link.rel === rel)?.href;
469
+ }
470
+
471
+ // src/resources/payment-handles.ts
472
+ var API_NAME = "payments";
473
+ var PaymentHandlesResource = class {
474
+ constructor(cfg, transport) {
475
+ this.cfg = cfg;
476
+ this.transport = transport;
477
+ }
478
+ cfg;
479
+ transport;
480
+ /**
481
+ * Tokenizes a payment instrument, returning a Payment Handle. If
482
+ * `req.accountId` is omitted, the client's default account ID is used.
483
+ */
484
+ async create(req, signal) {
485
+ const accountId = req.accountId ?? this.cfg.resolveAccountId();
486
+ const body = { ...req, accountId };
487
+ const url = `${this.cfg.paymentsUrl()}/paymenthandles`;
488
+ return this.transport.do({
489
+ api: API_NAME,
490
+ operation: "paymentHandles.create",
491
+ method: "POST",
492
+ url,
493
+ body,
494
+ signal
495
+ });
496
+ }
497
+ /**
498
+ * Retrieves a Payment Handle by ID. Useful for polling status if
499
+ * webhooks are not received; always verify via `get` after receiving a
500
+ * webhook before trusting the status.
501
+ */
502
+ async get(paymentHandleId, signal) {
503
+ const url = `${this.cfg.paymentsUrl()}/paymenthandles/${encodeURIComponent(paymentHandleId)}`;
504
+ return this.transport.do({
505
+ api: API_NAME,
506
+ operation: "paymentHandles.get",
507
+ method: "GET",
508
+ url,
509
+ signal
510
+ });
511
+ }
512
+ };
513
+ function paymentHandleRedirectUrl(handle) {
514
+ if (handle.action !== "REDIRECT") return void 0;
515
+ return findLinkByRel(handle.links, "payment_redirect");
516
+ }
517
+ function paymentHandleRequiresAction(handle) {
518
+ return handle.action === "REDIRECT";
519
+ }
520
+
521
+ // src/resources/payments.ts
522
+ var API_NAME2 = "payments";
523
+ var PaymentsResource = class {
524
+ constructor(cfg, transport) {
525
+ this.cfg = cfg;
526
+ this.transport = transport;
527
+ }
528
+ cfg;
529
+ transport;
530
+ /** Creates a payment using a `paymentHandleToken` from a `PAYABLE` Payment Handle. */
531
+ async create(req, signal) {
532
+ const url = `${this.cfg.paymentsUrl()}/payments`;
533
+ return this.transport.do({
534
+ api: API_NAME2,
535
+ operation: "payments.create",
536
+ method: "POST",
537
+ url,
538
+ body: req,
539
+ signal
540
+ });
541
+ }
542
+ /** Retrieves a payment by ID. */
543
+ async get(paymentId, signal) {
544
+ const url = `${this.cfg.paymentsUrl()}/payments/${encodeURIComponent(paymentId)}`;
545
+ return this.transport.do({
546
+ api: API_NAME2,
547
+ operation: "payments.get",
548
+ method: "GET",
549
+ url,
550
+ signal
551
+ });
552
+ }
553
+ /** Returns payments matching the given filter. */
554
+ async list(filter = {}, signal) {
555
+ const query = new URLSearchParams();
556
+ if (filter.merchantRefNum) query.set("merchantRefNum", filter.merchantRefNum);
557
+ if (filter.startDate) query.set("startDate", filter.startDate);
558
+ if (filter.endDate) query.set("endDate", filter.endDate);
559
+ if (filter.limit !== void 0) query.set("limit", String(filter.limit));
560
+ if (filter.offset !== void 0) query.set("offset", String(filter.offset));
561
+ const qs = query.toString();
562
+ const url = `${this.cfg.paymentsUrl()}/payments${qs ? `?${qs}` : ""}`;
563
+ const resp = await this.transport.do({
564
+ api: API_NAME2,
565
+ operation: "payments.list",
566
+ method: "GET",
567
+ url,
568
+ signal
569
+ });
570
+ return resp.payments;
571
+ }
572
+ /** Cancels an authorized (not-yet-settled) payment. */
573
+ async cancel(paymentId, signal) {
574
+ const url = `${this.cfg.paymentsUrl()}/payments/${encodeURIComponent(paymentId)}/cancels`;
575
+ return this.transport.do({
576
+ api: API_NAME2,
577
+ operation: "payments.cancel",
578
+ method: "POST",
579
+ url,
580
+ body: {},
581
+ signal
582
+ });
583
+ }
584
+ };
585
+
586
+ // src/resources/settlements.ts
587
+ var API_NAME3 = "payments";
588
+ var SettlementsResource = class {
589
+ constructor(cfg, transport) {
590
+ this.cfg = cfg;
591
+ this.transport = transport;
592
+ }
593
+ cfg;
594
+ transport;
595
+ /** Settles (captures) an authorized payment by payment ID. */
596
+ async create(paymentId, req, signal) {
597
+ const url = `${this.cfg.paymentsUrl()}/payments/${encodeURIComponent(paymentId)}/settlements`;
598
+ return this.transport.do({
599
+ api: API_NAME3,
600
+ operation: "settlements.create",
601
+ method: "POST",
602
+ url,
603
+ body: req,
604
+ signal
605
+ });
606
+ }
607
+ /** Retrieves a settlement by ID. */
608
+ async get(settlementId, signal) {
609
+ const url = `${this.cfg.paymentsUrl()}/settlements/${encodeURIComponent(settlementId)}`;
610
+ return this.transport.do({
611
+ api: API_NAME3,
612
+ operation: "settlements.get",
613
+ method: "GET",
614
+ url,
615
+ signal
616
+ });
617
+ }
618
+ /** Cancels a pending settlement. */
619
+ async cancel(settlementId, signal) {
620
+ const url = `${this.cfg.paymentsUrl()}/settlements/${encodeURIComponent(settlementId)}/cancels`;
621
+ return this.transport.do({
622
+ api: API_NAME3,
623
+ operation: "settlements.cancel",
624
+ method: "POST",
625
+ url,
626
+ body: {},
627
+ signal
628
+ });
629
+ }
630
+ };
631
+
632
+ // src/resources/refunds.ts
633
+ var API_NAME4 = "payments";
634
+ var RefundsResource = class {
635
+ constructor(cfg, transport) {
636
+ this.cfg = cfg;
637
+ this.transport = transport;
638
+ }
639
+ cfg;
640
+ transport;
641
+ /** Issues a refund for a completed payment or settlement. */
642
+ async create(settlementId, req, signal) {
643
+ const url = `${this.cfg.paymentsUrl()}/settlements/${encodeURIComponent(settlementId)}/refunds`;
644
+ return this.transport.do({
645
+ api: API_NAME4,
646
+ operation: "refunds.create",
647
+ method: "POST",
648
+ url,
649
+ body: req,
650
+ signal
651
+ });
652
+ }
653
+ /** Retrieves a refund by ID. */
654
+ async get(refundId, signal) {
655
+ const url = `${this.cfg.paymentsUrl()}/refunds/${encodeURIComponent(refundId)}`;
656
+ return this.transport.do({
657
+ api: API_NAME4,
658
+ operation: "refunds.get",
659
+ method: "GET",
660
+ url,
661
+ signal
662
+ });
663
+ }
664
+ /** Cancels a pending refund. */
665
+ async cancel(refundId, signal) {
666
+ const url = `${this.cfg.paymentsUrl()}/refunds/${encodeURIComponent(refundId)}/cancels`;
667
+ return this.transport.do({
668
+ api: API_NAME4,
669
+ operation: "refunds.cancel",
670
+ method: "POST",
671
+ url,
672
+ body: {},
673
+ signal
674
+ });
675
+ }
676
+ };
677
+
678
+ // src/resources/payouts.ts
679
+ var API_NAME5 = "payments";
680
+ var PayoutsResource = class {
681
+ constructor(cfg, transport) {
682
+ this.cfg = cfg;
683
+ this.transport = transport;
684
+ }
685
+ cfg;
686
+ transport;
687
+ /**
688
+ * Creates a standalone credit (payout for non-iGaming merchants). The
689
+ * Payment Handle must have `transactionType: "STANDALONE_CREDIT"`.
690
+ */
691
+ async standaloneCredit(req, signal) {
692
+ const accountId = req.accountId ?? this.cfg.resolveAccountId();
693
+ const body = { ...req, accountId };
694
+ const url = `${this.cfg.paymentsUrl()}/standalonecredits`;
695
+ return this.transport.do({
696
+ api: API_NAME5,
697
+ operation: "payouts.standaloneCredit",
698
+ method: "POST",
699
+ url,
700
+ body,
701
+ signal
702
+ });
703
+ }
704
+ /**
705
+ * Creates an original credit (payout for iGaming merchants). The
706
+ * Payment Handle must have `transactionType: "ORIGINAL_CREDIT"`.
707
+ */
708
+ async originalCredit(req, signal) {
709
+ const accountId = req.accountId ?? this.cfg.resolveAccountId();
710
+ const body = { ...req, accountId };
711
+ const url = `${this.cfg.paymentsUrl()}/originalcredits`;
712
+ return this.transport.do({
713
+ api: API_NAME5,
714
+ operation: "payouts.originalCredit",
715
+ method: "POST",
716
+ url,
717
+ body,
718
+ signal
719
+ });
720
+ }
721
+ /** Retrieves a standalone credit by ID. */
722
+ async getStandaloneCredit(creditId, signal) {
723
+ const url = `${this.cfg.paymentsUrl()}/standalonecredits/${encodeURIComponent(creditId)}`;
724
+ return this.transport.do({
725
+ api: API_NAME5,
726
+ operation: "payouts.getStandaloneCredit",
727
+ method: "GET",
728
+ url,
729
+ signal
730
+ });
731
+ }
732
+ /** Retrieves an original credit by ID. */
733
+ async getOriginalCredit(creditId, signal) {
734
+ const url = `${this.cfg.paymentsUrl()}/originalcredits/${encodeURIComponent(creditId)}`;
735
+ return this.transport.do({
736
+ api: API_NAME5,
737
+ operation: "payouts.getOriginalCredit",
738
+ method: "GET",
739
+ url,
740
+ signal
741
+ });
742
+ }
743
+ /** Cancels a standalone credit. */
744
+ async cancelStandaloneCredit(creditId, signal) {
745
+ const url = `${this.cfg.paymentsUrl()}/standalonecredits/${encodeURIComponent(creditId)}/cancels`;
746
+ return this.transport.do({
747
+ api: API_NAME5,
748
+ operation: "payouts.cancelStandaloneCredit",
749
+ method: "POST",
750
+ url,
751
+ body: {},
752
+ signal
753
+ });
754
+ }
755
+ };
756
+
757
+ // src/resources/verifications.ts
758
+ var API_NAME6 = "payments";
759
+ var VerificationsResource = class {
760
+ constructor(cfg, transport) {
761
+ this.cfg = cfg;
762
+ this.transport = transport;
763
+ }
764
+ cfg;
765
+ transport;
766
+ /** Creates a card verification. */
767
+ async create(req, signal) {
768
+ const url = `${this.cfg.paymentsUrl()}/verifications`;
769
+ return this.transport.do({
770
+ api: API_NAME6,
771
+ operation: "verifications.create",
772
+ method: "POST",
773
+ url,
774
+ body: req,
775
+ signal
776
+ });
777
+ }
778
+ /** Retrieves a verification by ID. */
779
+ async get(verificationId, signal) {
780
+ const url = `${this.cfg.paymentsUrl()}/verifications/${encodeURIComponent(verificationId)}`;
781
+ return this.transport.do({
782
+ api: API_NAME6,
783
+ operation: "verifications.get",
784
+ method: "GET",
785
+ url,
786
+ signal
787
+ });
788
+ }
789
+ };
790
+
791
+ // src/resources/customers.ts
792
+ var API_NAME7 = "payments";
793
+ var CustomersResource = class {
794
+ constructor(cfg, transport) {
795
+ this.cfg = cfg;
796
+ this.transport = transport;
797
+ }
798
+ cfg;
799
+ transport;
800
+ /** Creates a customer profile in the vault. */
801
+ async create(req, signal) {
802
+ const accountId = req.accountId ?? this.cfg.resolveAccountId();
803
+ const body = { ...req, accountId };
804
+ const url = `${this.cfg.paymentsUrl()}/customers`;
805
+ return this.transport.do({
806
+ api: API_NAME7,
807
+ operation: "customers.create",
808
+ method: "POST",
809
+ url,
810
+ body,
811
+ signal
812
+ });
813
+ }
814
+ /** Retrieves a customer profile by Paysafe's customer ID. */
815
+ async get(customerId, signal) {
816
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}`;
817
+ return this.transport.do({
818
+ api: API_NAME7,
819
+ operation: "customers.get",
820
+ method: "GET",
821
+ url,
822
+ signal
823
+ });
824
+ }
825
+ /** Retrieves a customer profile by your own `merchantCustomerId`. */
826
+ async getByMerchantCustomerId(merchantCustomerId, signal) {
827
+ const url = `${this.cfg.paymentsUrl()}/customers?merchantCustomerId=${encodeURIComponent(merchantCustomerId)}`;
828
+ return this.transport.do({
829
+ api: API_NAME7,
830
+ operation: "customers.getByMerchantCustomerId",
831
+ method: "GET",
832
+ url,
833
+ signal
834
+ });
835
+ }
836
+ /** Updates a customer profile. Only the fields set in `req` are changed server-side. */
837
+ async update(customerId, req, signal) {
838
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}`;
839
+ return this.transport.do({
840
+ api: API_NAME7,
841
+ operation: "customers.update",
842
+ method: "PUT",
843
+ url,
844
+ body: req,
845
+ signal
846
+ });
847
+ }
848
+ /** Deletes a customer profile. */
849
+ async delete(customerId, signal) {
850
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}`;
851
+ await this.transport.raw({
852
+ api: API_NAME7,
853
+ operation: "customers.delete",
854
+ method: "DELETE",
855
+ url,
856
+ signal
857
+ });
858
+ }
859
+ /**
860
+ * Converts a single-use token (SUT) returned from an initial payment
861
+ * into a multi-use token (MUT) attached to the customer profile,
862
+ * enabling saved-card/recurring flows.
863
+ */
864
+ async createPaymentHandle(customerId, req, signal) {
865
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}/paymenthandles`;
866
+ return this.transport.do({
867
+ api: API_NAME7,
868
+ operation: "customers.createPaymentHandle",
869
+ method: "POST",
870
+ url,
871
+ body: req,
872
+ signal
873
+ });
874
+ }
875
+ /** Lists all saved payment handles (saved instruments) for a customer. */
876
+ async listPaymentHandles(customerId, signal) {
877
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}/paymenthandles`;
878
+ const resp = await this.transport.do({
879
+ api: API_NAME7,
880
+ operation: "customers.listPaymentHandles",
881
+ method: "GET",
882
+ url,
883
+ signal
884
+ });
885
+ return resp.paymentHandles;
886
+ }
887
+ /** Deletes a specific saved payment handle for a customer. */
888
+ async deletePaymentHandle(customerId, handleId, signal) {
889
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}/paymenthandles/${encodeURIComponent(handleId)}`;
890
+ await this.transport.raw({
891
+ api: API_NAME7,
892
+ operation: "customers.deletePaymentHandle",
893
+ method: "DELETE",
894
+ url,
895
+ signal
896
+ });
897
+ }
898
+ /**
899
+ * Tokenizes the customer's entire saved profile — profile details,
900
+ * saved cards, addresses, and bank mandates — into one short-lived
901
+ * token valid for 900 seconds. Used to display a returning customer's
902
+ * saved instruments, or to re-collect a one-time CVV for a saved card.
903
+ */
904
+ async createSingleUseCustomerToken(customerId, signal) {
905
+ const url = `${this.cfg.paymentsUrl()}/customers/${encodeURIComponent(customerId)}/singleusecustomertokens`;
906
+ return this.transport.do({
907
+ api: API_NAME7,
908
+ operation: "customers.createSingleUseCustomerToken",
909
+ method: "POST",
910
+ url,
911
+ body: {},
912
+ signal
913
+ });
914
+ }
915
+ };
916
+
917
+ // src/resources/applications.ts
918
+ var API_NAME8 = "applications";
919
+ var ApplicationsResource = class {
920
+ constructor(cfg, transport) {
921
+ this.cfg = cfg;
922
+ this.transport = transport;
923
+ }
924
+ cfg;
925
+ transport;
926
+ /** Creates a draft merchant application. */
927
+ async create(req, signal) {
928
+ const url = `${this.cfg.applicationsUrl()}/applications`;
929
+ return this.transport.do({
930
+ api: API_NAME8,
931
+ operation: "applications.create",
932
+ method: "POST",
933
+ url,
934
+ body: req,
935
+ signal
936
+ });
937
+ }
938
+ /** Retrieves an application by ID. */
939
+ async get(applicationId, signal) {
940
+ const url = `${this.cfg.applicationsUrl()}/applications/${encodeURIComponent(applicationId)}`;
941
+ return this.transport.do({
942
+ api: API_NAME8,
943
+ operation: "applications.get",
944
+ method: "GET",
945
+ url,
946
+ signal
947
+ });
948
+ }
949
+ /** Updates a draft application. Only possible before `submit` is called. */
950
+ async update(applicationId, req, signal) {
951
+ const url = `${this.cfg.applicationsUrl()}/applications/${encodeURIComponent(applicationId)}`;
952
+ return this.transport.do({
953
+ api: API_NAME8,
954
+ operation: "applications.update",
955
+ method: "PUT",
956
+ url,
957
+ body: req,
958
+ signal
959
+ });
960
+ }
961
+ /**
962
+ * Sends the application to Paysafe for review. After this call
963
+ * succeeds, the application can no longer be modified via the API.
964
+ */
965
+ async submit(applicationId, signal) {
966
+ const url = `${this.cfg.applicationsUrl()}/applications/${encodeURIComponent(applicationId)}`;
967
+ return this.transport.do({
968
+ api: API_NAME8,
969
+ operation: "applications.submit",
970
+ method: "PATCH",
971
+ url,
972
+ body: {},
973
+ signal
974
+ });
975
+ }
976
+ /** Retrieves the terms the merchant must accept before processing can begin. */
977
+ async getTermsAndConditions(applicationId, signal) {
978
+ const url = `${this.cfg.applicationsUrl()}/applications/${encodeURIComponent(applicationId)}/termsandconditions`;
979
+ return this.transport.do({
980
+ api: API_NAME8,
981
+ operation: "applications.getTermsAndConditions",
982
+ method: "GET",
983
+ url,
984
+ signal
985
+ });
986
+ }
987
+ /**
988
+ * Attaches a supporting document to an application (e.g. requested by
989
+ * a credit underwriter during review). Documents can be uploaded before
990
+ * or after submission.
991
+ */
992
+ async uploadDocument(applicationId, req, signal) {
993
+ const url = `${this.cfg.applicationsUrl()}/applications/${encodeURIComponent(applicationId)}/documents`;
994
+ return this.transport.do({
995
+ api: API_NAME8,
996
+ operation: "applications.uploadDocument",
997
+ method: "POST",
998
+ url,
999
+ body: req,
1000
+ signal
1001
+ });
1002
+ }
1003
+ };
1004
+
1005
+ // src/resources/plans.ts
1006
+ var API_NAME9 = "scheduler";
1007
+ var PlansResource = class {
1008
+ constructor(cfg, transport) {
1009
+ this.cfg = cfg;
1010
+ this.transport = transport;
1011
+ }
1012
+ cfg;
1013
+ transport;
1014
+ /**
1015
+ * Creates a recurring billing plan under `accountId` (or the client's
1016
+ * default account ID if `accountId` is omitted).
1017
+ */
1018
+ async create(accountId, req, signal) {
1019
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1020
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/plans`;
1021
+ return this.transport.do({
1022
+ api: API_NAME9,
1023
+ operation: "plans.create",
1024
+ method: "POST",
1025
+ url,
1026
+ body: req,
1027
+ signal
1028
+ });
1029
+ }
1030
+ /** Retrieves a plan by ID. */
1031
+ async get(accountId, planId, signal) {
1032
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1033
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/plans/${encodeURIComponent(planId)}`;
1034
+ return this.transport.do({
1035
+ api: API_NAME9,
1036
+ operation: "plans.get",
1037
+ method: "GET",
1038
+ url,
1039
+ signal
1040
+ });
1041
+ }
1042
+ /** Lists all billing plans for an account. */
1043
+ async list(accountId, signal) {
1044
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1045
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/plans`;
1046
+ const resp = await this.transport.do({
1047
+ api: API_NAME9,
1048
+ operation: "plans.list",
1049
+ method: "GET",
1050
+ url,
1051
+ signal
1052
+ });
1053
+ return resp.plans;
1054
+ }
1055
+ /**
1056
+ * Updates a plan's mutable fields. Keep amount increases below 20% to
1057
+ * comply with card scheme guidelines. Discontinuing a plan prevents new
1058
+ * subscriptions but does not affect existing ones.
1059
+ */
1060
+ async update(accountId, planId, req, signal) {
1061
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1062
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/plans/${encodeURIComponent(planId)}`;
1063
+ return this.transport.do({
1064
+ api: API_NAME9,
1065
+ operation: "plans.update",
1066
+ method: "PATCH",
1067
+ url,
1068
+ body: req,
1069
+ signal
1070
+ });
1071
+ }
1072
+ /** Discontinues a plan. */
1073
+ async delete(accountId, planId, signal) {
1074
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1075
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/plans/${encodeURIComponent(planId)}`;
1076
+ await this.transport.raw({
1077
+ api: API_NAME9,
1078
+ operation: "plans.delete",
1079
+ method: "DELETE",
1080
+ url,
1081
+ signal
1082
+ });
1083
+ }
1084
+ };
1085
+
1086
+ // src/resources/subscriptions.ts
1087
+ var API_NAME10 = "scheduler";
1088
+ var SubscriptionsResource = class {
1089
+ constructor(cfg, transport) {
1090
+ this.cfg = cfg;
1091
+ this.transport = transport;
1092
+ }
1093
+ cfg;
1094
+ transport;
1095
+ /** Creates a subscription for a customer under a plan. */
1096
+ async create(accountId, req, signal) {
1097
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1098
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/subscriptions`;
1099
+ return this.transport.do({
1100
+ api: API_NAME10,
1101
+ operation: "subscriptions.create",
1102
+ method: "POST",
1103
+ url,
1104
+ body: req,
1105
+ signal
1106
+ });
1107
+ }
1108
+ /** Retrieves a subscription by ID. */
1109
+ async get(accountId, subscriptionId, signal) {
1110
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1111
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/subscriptions/${encodeURIComponent(subscriptionId)}`;
1112
+ return this.transport.do({
1113
+ api: API_NAME10,
1114
+ operation: "subscriptions.get",
1115
+ method: "GET",
1116
+ url,
1117
+ signal
1118
+ });
1119
+ }
1120
+ /** Lists subscriptions matching the given filter. */
1121
+ async list(accountId, filter = {}, signal) {
1122
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1123
+ const query = new URLSearchParams();
1124
+ if (filter.planId) query.set("planId", filter.planId);
1125
+ if (filter.status) query.set("status", filter.status);
1126
+ if (filter.merchantCustomerId) query.set("merchantCustomerId", filter.merchantCustomerId);
1127
+ if (filter.limit !== void 0) query.set("limit", String(filter.limit));
1128
+ if (filter.offset !== void 0) query.set("offset", String(filter.offset));
1129
+ const qs = query.toString();
1130
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/subscriptions${qs ? `?${qs}` : ""}`;
1131
+ const resp = await this.transport.do({
1132
+ api: API_NAME10,
1133
+ operation: "subscriptions.list",
1134
+ method: "GET",
1135
+ url,
1136
+ signal
1137
+ });
1138
+ return resp.subscriptions;
1139
+ }
1140
+ /**
1141
+ * Updates a subscription: extend cycles (`numCycles`), apply a discount
1142
+ * (`discountAmount`/`discountNumPayments`), or change `status` directly.
1143
+ * Prefer `cancel`/`suspend`/`reactivate` for status transitions.
1144
+ */
1145
+ async update(accountId, subscriptionId, req, signal) {
1146
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1147
+ const url = `${this.cfg.schedulerUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/subscriptions/${encodeURIComponent(subscriptionId)}`;
1148
+ return this.transport.do({
1149
+ api: API_NAME10,
1150
+ operation: "subscriptions.update",
1151
+ method: "PATCH",
1152
+ url,
1153
+ body: req,
1154
+ signal
1155
+ });
1156
+ }
1157
+ /** Cancels a subscription immediately. */
1158
+ async cancel(accountId, subscriptionId, signal) {
1159
+ return this.update(accountId, subscriptionId, { status: "CANCELLED" }, signal);
1160
+ }
1161
+ /** Pauses billing on a subscription; it can later be reactivated. */
1162
+ async suspend(accountId, subscriptionId, signal) {
1163
+ return this.update(accountId, subscriptionId, { status: "SUSPENDED" }, signal);
1164
+ }
1165
+ /**
1166
+ * Re-activates a suspended subscription. The last failed payment is
1167
+ * retried; subsequent cycles resume on their original schedule.
1168
+ */
1169
+ async reactivate(accountId, subscriptionId, signal) {
1170
+ return this.update(accountId, subscriptionId, { status: "ACTIVE" }, signal);
1171
+ }
1172
+ };
1173
+
1174
+ // src/resources/fx-rates.ts
1175
+ var API_NAME11 = "fx_rates";
1176
+ var FxRatesResource = class {
1177
+ constructor(cfg, transport) {
1178
+ this.cfg = cfg;
1179
+ this.transport = transport;
1180
+ }
1181
+ cfg;
1182
+ transport;
1183
+ /** Gets a guaranteed FX rate for a currency pair. */
1184
+ async getRate(accountId, req, signal) {
1185
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1186
+ const url = `${this.cfg.fxRatesUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/fxrates`;
1187
+ return this.transport.do({
1188
+ api: API_NAME11,
1189
+ operation: "fxRates.getRate",
1190
+ method: "POST",
1191
+ url,
1192
+ body: req,
1193
+ signal
1194
+ });
1195
+ }
1196
+ /** Retrieves a specific FX rate by quote ID. */
1197
+ async getQuote(accountId, quoteId, signal) {
1198
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1199
+ const url = `${this.cfg.fxRatesUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/fxrates/${encodeURIComponent(quoteId)}`;
1200
+ return this.transport.do({
1201
+ api: API_NAME11,
1202
+ operation: "fxRates.getQuote",
1203
+ method: "GET",
1204
+ url,
1205
+ signal
1206
+ });
1207
+ }
1208
+ };
1209
+
1210
+ // src/resources/customer-identity.ts
1211
+ var API_NAME12 = "customer_identity";
1212
+ var CustomerIdentityResource = class {
1213
+ constructor(cfg, transport) {
1214
+ this.cfg = cfg;
1215
+ this.transport = transport;
1216
+ }
1217
+ cfg;
1218
+ transport;
1219
+ /** Submits an identity verification request. */
1220
+ async verify(req, signal) {
1221
+ const url = `${this.cfg.customerIdentificationUrl()}/identityprofiles`;
1222
+ return this.transport.do({
1223
+ api: API_NAME12,
1224
+ operation: "customerIdentity.verify",
1225
+ method: "POST",
1226
+ url,
1227
+ body: req,
1228
+ signal
1229
+ });
1230
+ }
1231
+ /** Retrieves a previously submitted identity profile by ID. */
1232
+ async get(profileId, signal) {
1233
+ const url = `${this.cfg.customerIdentificationUrl()}/identityprofiles/${encodeURIComponent(profileId)}`;
1234
+ return this.transport.do({
1235
+ api: API_NAME12,
1236
+ operation: "customerIdentity.get",
1237
+ method: "GET",
1238
+ url,
1239
+ signal
1240
+ });
1241
+ }
1242
+ /**
1243
+ * Reruns a failed identity check. Only rerun a check whose `decision`
1244
+ * was `"ERROR"` — this indicates a transient downstream provider
1245
+ * issue. Do not rerun a check whose `decision` was `"FAIL"`;
1246
+ * resubmitting returns the same `"FAIL"` result again.
1247
+ */
1248
+ async rerun(profileId, signal) {
1249
+ const url = `${this.cfg.customerIdentificationUrl()}/identityprofiles/${encodeURIComponent(profileId)}/rerunfailedchecks`;
1250
+ return this.transport.do({
1251
+ api: API_NAME12,
1252
+ operation: "customerIdentity.rerun",
1253
+ method: "POST",
1254
+ url,
1255
+ body: {},
1256
+ signal
1257
+ });
1258
+ }
1259
+ };
1260
+
1261
+ // src/resources/bank-account-validation.ts
1262
+ var BankAccountValidationResource = class {
1263
+ constructor(cfg, transport) {
1264
+ this.cfg = cfg;
1265
+ this.transport = transport;
1266
+ }
1267
+ cfg;
1268
+ transport;
1269
+ /**
1270
+ * Starts a bank account verification session. Redirect the customer to
1271
+ * {@link bankVerificationRedirectUrl} to complete the flow; there is no
1272
+ * synchronous result.
1273
+ */
1274
+ async create(accountId, req, signal) {
1275
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1276
+ const url = `${this.cfg.bankAccountValidatorUrl()}/accounts/${encodeURIComponent(resolvedAccountId)}/verifications`;
1277
+ return this.transport.do({
1278
+ api: "bank_account_validation",
1279
+ operation: "bankAccountValidation.create",
1280
+ method: "POST",
1281
+ url,
1282
+ body: req,
1283
+ signal
1284
+ });
1285
+ }
1286
+ /**
1287
+ * Looks up a bank account verification by ID. Returns validated
1288
+ * account details and a single-use payment token once the customer has
1289
+ * completed the redirect flow.
1290
+ */
1291
+ async get(verificationId, signal) {
1292
+ const url = `${this.cfg.bankAccountValidatorUrl()}/verifications/${encodeURIComponent(verificationId)}`;
1293
+ return this.transport.do({
1294
+ api: "bank_account_validation",
1295
+ operation: "bankAccountValidation.get",
1296
+ method: "GET",
1297
+ url,
1298
+ signal
1299
+ });
1300
+ }
1301
+ };
1302
+ var InteracVerificationResource = class {
1303
+ constructor(cfg, transport) {
1304
+ this.cfg = cfg;
1305
+ this.transport = transport;
1306
+ }
1307
+ cfg;
1308
+ transport;
1309
+ /** Starts an Interac AML Assist verification session. */
1310
+ async create(accountId, req, signal) {
1311
+ const resolvedAccountId = this.cfg.resolveAccountId(accountId);
1312
+ const url = `${this.cfg.bankAccountValidatorUrl()}/verifiedme/accounts/${encodeURIComponent(resolvedAccountId)}/verifications`;
1313
+ return this.transport.do({
1314
+ api: "interac_verification",
1315
+ operation: "interacVerification.create",
1316
+ method: "POST",
1317
+ url,
1318
+ body: req,
1319
+ signal
1320
+ });
1321
+ }
1322
+ /**
1323
+ * Fetches the user's verified information once they have completed the
1324
+ * redirect flow on Interac's bank page.
1325
+ */
1326
+ async get(verificationId, signal) {
1327
+ const url = `${this.cfg.bankAccountValidatorUrl()}/verifiedme/verifications/${encodeURIComponent(verificationId)}`;
1328
+ return this.transport.do({
1329
+ api: "interac_verification",
1330
+ operation: "interacVerification.get",
1331
+ method: "GET",
1332
+ url,
1333
+ signal
1334
+ });
1335
+ }
1336
+ };
1337
+ function bankVerificationRedirectUrl(verification) {
1338
+ return findLinkByRel(verification.links, "redirect_bank_validation");
1339
+ }
1340
+
1341
+ // src/core/webhook-crypto.ts
1342
+ var encoder = new TextEncoder();
1343
+ function isNodeRuntime() {
1344
+ return typeof process !== "undefined" && typeof process.versions === "object" && typeof process.versions.node === "string";
1345
+ }
1346
+ async function hmacSha256Base64Node(key, data) {
1347
+ const nodeCrypto = await import('crypto');
1348
+ const mac = nodeCrypto.createHmac("sha256", key);
1349
+ mac.update(data);
1350
+ return mac.digest("base64");
1351
+ }
1352
+ async function hmacSha256Base64WebCrypto(key, data) {
1353
+ const subtle = globalThis.crypto?.subtle;
1354
+ if (!subtle) {
1355
+ throw new Error(
1356
+ "No HMAC implementation available: neither node:crypto nor globalThis.crypto.subtle is present in this runtime."
1357
+ );
1358
+ }
1359
+ const cryptoKey = await subtle.importKey(
1360
+ "raw",
1361
+ encoder.encode(key),
1362
+ { name: "HMAC", hash: "SHA-256" },
1363
+ false,
1364
+ ["sign"]
1365
+ );
1366
+ const signature = await subtle.sign("HMAC", cryptoKey, data);
1367
+ return bufferToBase64(new Uint8Array(signature));
1368
+ }
1369
+ function bufferToBase64(bytes) {
1370
+ if (typeof Buffer !== "undefined") {
1371
+ return Buffer.from(bytes).toString("base64");
1372
+ }
1373
+ let binary = "";
1374
+ for (const byte of bytes) {
1375
+ binary += String.fromCharCode(byte);
1376
+ }
1377
+ return btoa(binary);
1378
+ }
1379
+ async function hmacSha256Base64(key, data) {
1380
+ const bytes = typeof data === "string" ? encoder.encode(data) : data;
1381
+ return isNodeRuntime() ? hmacSha256Base64Node(key, bytes) : hmacSha256Base64WebCrypto(key, bytes);
1382
+ }
1383
+ async function timingSafeStringEqual(a, b) {
1384
+ if (isNodeRuntime()) {
1385
+ const nodeCrypto = await import('crypto');
1386
+ const bufA = Buffer.from(a, "utf-8");
1387
+ const bufB = Buffer.from(b, "utf-8");
1388
+ if (bufA.length !== bufB.length) {
1389
+ nodeCrypto.timingSafeEqual(bufA, bufA);
1390
+ return false;
1391
+ }
1392
+ return nodeCrypto.timingSafeEqual(bufA, bufB);
1393
+ }
1394
+ const bytesA = encoder.encode(a);
1395
+ const bytesB = encoder.encode(b);
1396
+ const length = Math.max(bytesA.length, bytesB.length);
1397
+ let mismatch = bytesA.length === bytesB.length ? 0 : 1;
1398
+ for (let i = 0; i < length; i++) {
1399
+ const byteA = bytesA[i] ?? 0;
1400
+ const byteB = bytesB[i] ?? 0;
1401
+ mismatch |= byteA ^ byteB;
1402
+ }
1403
+ return mismatch === 0;
1404
+ }
1405
+
1406
+ // src/resources/webhooks.ts
1407
+ var WebhooksResource = class {
1408
+ /**
1409
+ * Verifies the HMAC-SHA256 signature of `rawBody` against `signature`
1410
+ * using `hmacKey`, then decodes the payload into a
1411
+ * {@link PaysafeWebhookEvent}.
1412
+ *
1413
+ * @param rawBody - The exact, unmodified request body bytes/text as received.
1414
+ * @param signature - The value of the `Signature` HTTP header.
1415
+ * @param hmacKey - The merchant's webhook HMAC key from the Paysafe portal.
1416
+ *
1417
+ * Verification uses a constant-time comparison to prevent timing
1418
+ * attacks.
1419
+ */
1420
+ async verifyAndParse(rawBody, signature, hmacKey) {
1421
+ await this.verifySignature(rawBody, signature, hmacKey);
1422
+ return this.parse(rawBody);
1423
+ }
1424
+ /**
1425
+ * Verifies the webhook signature without parsing the body. Resolves on
1426
+ * success, or throws a {@link PaysafeError} with
1427
+ * `kind === "webhook_signature_mismatch"` on failure.
1428
+ */
1429
+ async verifySignature(rawBody, signature, hmacKey) {
1430
+ const expected = await hmacSha256Base64(hmacKey, rawBody);
1431
+ const matches = await timingSafeStringEqual(expected, signature);
1432
+ if (!matches) {
1433
+ throw PaysafeError.webhookMismatch();
1434
+ }
1435
+ }
1436
+ /**
1437
+ * Decodes a webhook body that has already been verified (e.g. by a
1438
+ * signature-checking middleware) into a {@link PaysafeWebhookEvent}.
1439
+ */
1440
+ parse(rawBody) {
1441
+ const text = typeof rawBody === "string" ? rawBody : new TextDecoder().decode(rawBody);
1442
+ try {
1443
+ return JSON.parse(text);
1444
+ } catch (cause) {
1445
+ throw PaysafeError.decodeError(cause);
1446
+ }
1447
+ }
1448
+ /**
1449
+ * Parses an already-decoded object into a {@link PaysafeWebhookEvent},
1450
+ * useful when the caller's web framework has already deserialized the
1451
+ * JSON body.
1452
+ */
1453
+ parseObject(obj) {
1454
+ return obj;
1455
+ }
1456
+ };
1457
+ function webhookTopic(event) {
1458
+ const name = event.eventName;
1459
+ if (name.startsWith("PAYMENT_HANDLE_")) return "payment_handle";
1460
+ if (name.startsWith("PAYMENT_")) return "payment";
1461
+ if (name.startsWith("SETTLEMENT_")) return "settlement";
1462
+ if (name.startsWith("REFUND_")) return "refund";
1463
+ if (name.startsWith("STANDALONE_CREDIT_") || name.startsWith("ORIGINAL_CREDIT_")) return "payout";
1464
+ if (name.startsWith("SUBSCRIPTION_")) return "subscription";
1465
+ if (name.startsWith("ACCOUNT_UPDATER_")) return "account_updater";
1466
+ return "unknown";
1467
+ }
1468
+ var PAYMENT_HANDLE_STATUS_BY_EVENT = {
1469
+ PAYMENT_HANDLE_INITIATED: "INITIATED",
1470
+ PAYMENT_HANDLE_PROCESSING: "PROCESSING",
1471
+ PAYMENT_HANDLE_PAYABLE: "PAYABLE",
1472
+ PAYMENT_HANDLE_COMPLETED: "COMPLETED",
1473
+ PAYMENT_HANDLE_FAILED: "FAILED",
1474
+ PAYMENT_HANDLE_EXPIRED: "EXPIRED",
1475
+ PAYMENT_HANDLE_CANCELLED: "CANCELLED"
1476
+ };
1477
+ function webhookPaymentHandleStatus(event) {
1478
+ return PAYMENT_HANDLE_STATUS_BY_EVENT[event.eventName];
1479
+ }
1480
+
1481
+ // src/client.ts
1482
+ var PaysafeClient = class _PaysafeClient {
1483
+ cfg;
1484
+ // Payments API
1485
+ paymentHandles;
1486
+ payments;
1487
+ settlements;
1488
+ refunds;
1489
+ payouts;
1490
+ verifications;
1491
+ customers;
1492
+ // Payment Scheduler API
1493
+ plans;
1494
+ subscriptions;
1495
+ // Applications (Onboarding) API
1496
+ applications;
1497
+ // Value Added Services
1498
+ fxRates;
1499
+ customerIdentity;
1500
+ bankAccountValidation;
1501
+ interacVerification;
1502
+ // Webhooks
1503
+ webhooks;
1504
+ constructor(options, telemetryHook) {
1505
+ this.cfg = new ResolvedConfig(options);
1506
+ const limiter = new RateLimiter();
1507
+ const transport = new HttpTransport(this.cfg, limiter, telemetryHook);
1508
+ this.paymentHandles = new PaymentHandlesResource(this.cfg, transport);
1509
+ this.payments = new PaymentsResource(this.cfg, transport);
1510
+ this.settlements = new SettlementsResource(this.cfg, transport);
1511
+ this.refunds = new RefundsResource(this.cfg, transport);
1512
+ this.payouts = new PayoutsResource(this.cfg, transport);
1513
+ this.verifications = new VerificationsResource(this.cfg, transport);
1514
+ this.customers = new CustomersResource(this.cfg, transport);
1515
+ this.plans = new PlansResource(this.cfg, transport);
1516
+ this.subscriptions = new SubscriptionsResource(this.cfg, transport);
1517
+ this.applications = new ApplicationsResource(this.cfg, transport);
1518
+ this.fxRates = new FxRatesResource(this.cfg, transport);
1519
+ this.customerIdentity = new CustomerIdentityResource(this.cfg, transport);
1520
+ this.bankAccountValidation = new BankAccountValidationResource(this.cfg, transport);
1521
+ this.interacVerification = new InteracVerificationResource(this.cfg, transport);
1522
+ this.webhooks = new WebhooksResource();
1523
+ }
1524
+ /**
1525
+ * Builds a `PaysafeClient` from `PAYSAFE_USERNAME`, `PAYSAFE_PASSWORD`,
1526
+ * `PAYSAFE_ENVIRONMENT`, and `PAYSAFE_ACCOUNT_ID` environment variables
1527
+ * (Node.js only), merged with any additional `overrides` (last-wins).
1528
+ */
1529
+ static fromEnv(overrides = {}, telemetryHook) {
1530
+ return new _PaysafeClient(configFromEnv(overrides), telemetryHook);
1531
+ }
1532
+ /** The client's configured default account ID, if set. */
1533
+ get accountId() {
1534
+ return this.cfg.accountId;
1535
+ }
1536
+ /** The client's configured environment (`"test"` or `"production"`). */
1537
+ get environment() {
1538
+ return this.cfg.environment;
1539
+ }
1540
+ /** The resolved base URL the client sends requests to. */
1541
+ get baseUrl() {
1542
+ return this.cfg.baseUrl();
1543
+ }
1544
+ };
1545
+
1546
+ export { ApplicationsResource, BankAccountValidationResource, CustomerIdentityResource, CustomersResource, FxRatesResource, InteracVerificationResource, PaymentHandlesResource, PaymentsResource, PayoutsResource, PaysafeClient, PaysafeError, PlansResource, RefundsResource, SettlementsResource, SubscriptionsResource, VerificationsResource, WebhooksResource, bankVerificationRedirectUrl, findLinkByRel, paymentHandleRedirectUrl, paymentHandleRequiresAction, webhookPaymentHandleStatus, webhookTopic };
1547
+ //# sourceMappingURL=index.js.map
1548
+ //# sourceMappingURL=index.js.map