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