@imerchantsolutions/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.mjs ADDED
@@ -0,0 +1,706 @@
1
+ // src/errors.ts
2
+ var iMerchantError = class _iMerchantError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "iMerchantError";
6
+ Object.setPrototypeOf(this, _iMerchantError.prototype);
7
+ }
8
+ };
9
+ var APIError = class _APIError extends iMerchantError {
10
+ constructor(message, statusCode, code, details) {
11
+ super(message);
12
+ this.name = "APIError";
13
+ this.statusCode = statusCode;
14
+ this.code = code;
15
+ this.details = details;
16
+ Object.setPrototypeOf(this, _APIError.prototype);
17
+ }
18
+ };
19
+ var AuthenticationError = class _AuthenticationError extends iMerchantError {
20
+ constructor(message = "Invalid API key provided") {
21
+ super(message);
22
+ this.name = "AuthenticationError";
23
+ Object.setPrototypeOf(this, _AuthenticationError.prototype);
24
+ }
25
+ };
26
+ var NotFoundError = class _NotFoundError extends APIError {
27
+ constructor(resource, id) {
28
+ super(`${resource} with ID '${id}' not found`, 404, "not_found");
29
+ this.name = "NotFoundError";
30
+ Object.setPrototypeOf(this, _NotFoundError.prototype);
31
+ }
32
+ };
33
+ var ValidationError = class _ValidationError extends APIError {
34
+ constructor(message, errors) {
35
+ super(message, 400, "validation_error", { errors });
36
+ this.name = "ValidationError";
37
+ this.errors = errors;
38
+ Object.setPrototypeOf(this, _ValidationError.prototype);
39
+ }
40
+ };
41
+ var RateLimitError = class _RateLimitError extends APIError {
42
+ constructor(retryAfter) {
43
+ super(
44
+ "Rate limit exceeded. Please slow down your requests.",
45
+ 429,
46
+ "rate_limit_exceeded",
47
+ { retryAfter }
48
+ );
49
+ this.name = "RateLimitError";
50
+ this.retryAfter = retryAfter;
51
+ Object.setPrototypeOf(this, _RateLimitError.prototype);
52
+ }
53
+ };
54
+ var WebhookSignatureError = class _WebhookSignatureError extends iMerchantError {
55
+ constructor(message = "Invalid webhook signature") {
56
+ super(message);
57
+ this.name = "WebhookSignatureError";
58
+ Object.setPrototypeOf(this, _WebhookSignatureError.prototype);
59
+ }
60
+ };
61
+
62
+ // src/http.ts
63
+ var DEFAULT_BASE_URL = "https://api.imerchant.com";
64
+ var DEFAULT_TIMEOUT = 3e4;
65
+ var DEFAULT_API_VERSION = "v1";
66
+ var HttpClient = class {
67
+ constructor(config) {
68
+ if (!config.apiKey) {
69
+ throw new AuthenticationError("API key is required");
70
+ }
71
+ this.config = {
72
+ apiKey: config.apiKey,
73
+ baseUrl: config.baseUrl || DEFAULT_BASE_URL,
74
+ timeout: config.timeout || DEFAULT_TIMEOUT,
75
+ apiVersion: config.apiVersion || DEFAULT_API_VERSION
76
+ };
77
+ }
78
+ getUrl(path) {
79
+ const baseUrl = this.config.baseUrl.replace(/\/$/, "");
80
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
81
+ return `${baseUrl}/${this.config.apiVersion}${cleanPath}`;
82
+ }
83
+ async handleResponse(response) {
84
+ const contentType = response.headers.get("content-type");
85
+ const isJson = contentType?.includes("application/json");
86
+ if (!response.ok) {
87
+ let errorData = {};
88
+ if (isJson) {
89
+ try {
90
+ const jsonData = await response.json();
91
+ errorData = jsonData;
92
+ } catch {
93
+ }
94
+ }
95
+ const message = errorData.message || `Request failed with status ${response.status}`;
96
+ const code = errorData.code || "unknown_error";
97
+ switch (response.status) {
98
+ case 401:
99
+ throw new AuthenticationError(message);
100
+ case 400:
101
+ if (errorData.errors) {
102
+ throw new ValidationError(message, errorData.errors);
103
+ }
104
+ throw new APIError(message, response.status, code);
105
+ case 429:
106
+ const retryAfter = response.headers.get("retry-after");
107
+ throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
108
+ default:
109
+ throw new APIError(message, response.status, code);
110
+ }
111
+ }
112
+ if (!isJson) {
113
+ return {};
114
+ }
115
+ return response.json();
116
+ }
117
+ async request(method, path, data, options) {
118
+ const url = this.getUrl(path);
119
+ const timeout = options?.timeout || this.config.timeout;
120
+ const headers = {
121
+ "Authorization": `Bearer ${this.config.apiKey}`,
122
+ "Content-Type": "application/json",
123
+ "X-SDK-Version": "1.0.0"
124
+ };
125
+ if (options?.idempotencyKey) {
126
+ headers["Idempotency-Key"] = options.idempotencyKey;
127
+ }
128
+ const controller = new AbortController();
129
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
130
+ try {
131
+ const response = await fetch(url, {
132
+ method,
133
+ headers,
134
+ body: data ? JSON.stringify(data) : void 0,
135
+ signal: controller.signal
136
+ });
137
+ return this.handleResponse(response);
138
+ } catch (error) {
139
+ if (error instanceof Error && error.name === "AbortError") {
140
+ throw new APIError("Request timed out", 408, "timeout");
141
+ }
142
+ throw error;
143
+ } finally {
144
+ clearTimeout(timeoutId);
145
+ }
146
+ }
147
+ get(path, options) {
148
+ return this.request("GET", path, void 0, options);
149
+ }
150
+ post(path, data, options) {
151
+ return this.request("POST", path, data, options);
152
+ }
153
+ put(path, data, options) {
154
+ return this.request("PUT", path, data, options);
155
+ }
156
+ patch(path, data, options) {
157
+ return this.request("PATCH", path, data, options);
158
+ }
159
+ delete(path, options) {
160
+ return this.request("DELETE", path, void 0, options);
161
+ }
162
+ };
163
+
164
+ // src/resources/payments.ts
165
+ var Payments = class {
166
+ constructor(http) {
167
+ this.http = http;
168
+ }
169
+ /**
170
+ * Create a new payment
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const payment = await client.payments.create({
175
+ * amount: 1000, // $10.00 in cents
176
+ * currency: 'usd',
177
+ * reference: 'order_123',
178
+ * description: 'Test payment',
179
+ * });
180
+ * ```
181
+ */
182
+ async create(params, options) {
183
+ return this.http.post("/payments", params, options);
184
+ }
185
+ /**
186
+ * Retrieve a payment by ID
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * const payment = await client.payments.retrieve('pay_abc123');
191
+ * console.log(payment.status);
192
+ * ```
193
+ */
194
+ async retrieve(id, options) {
195
+ return this.http.get(`/payments/${id}`, options);
196
+ }
197
+ /**
198
+ * List all payments with optional filters
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const { data, hasMore } = await client.payments.list({
203
+ * status: 'captured',
204
+ * limit: 10,
205
+ * });
206
+ * ```
207
+ */
208
+ async list(params, options) {
209
+ const searchParams = new URLSearchParams();
210
+ if (params?.limit) searchParams.set("limit", params.limit.toString());
211
+ if (params?.cursor) searchParams.set("cursor", params.cursor);
212
+ if (params?.status) searchParams.set("status", params.status);
213
+ if (params?.customerId) searchParams.set("customerId", params.customerId);
214
+ if (params?.createdAfter) searchParams.set("createdAfter", params.createdAfter);
215
+ if (params?.createdBefore) searchParams.set("createdBefore", params.createdBefore);
216
+ const query = searchParams.toString();
217
+ const path = query ? `/payments?${query}` : "/payments";
218
+ return this.http.get(path, options);
219
+ }
220
+ /**
221
+ * Capture an authorized payment
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * // Capture full amount
226
+ * const payment = await client.payments.capture('pay_abc123');
227
+ *
228
+ * // Capture partial amount
229
+ * const payment = await client.payments.capture('pay_abc123', { amount: 500 });
230
+ * ```
231
+ */
232
+ async capture(id, params, options) {
233
+ return this.http.post(`/payments/${id}/capture`, params || {}, options);
234
+ }
235
+ /**
236
+ * Cancel an authorized payment
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const payment = await client.payments.cancel('pay_abc123');
241
+ * ```
242
+ */
243
+ async cancel(id, options) {
244
+ return this.http.post(`/payments/${id}/cancel`, {}, options);
245
+ }
246
+ };
247
+
248
+ // src/resources/refunds.ts
249
+ var Refunds = class {
250
+ constructor(http) {
251
+ this.http = http;
252
+ }
253
+ /**
254
+ * Create a refund for a payment
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Full refund
259
+ * const refund = await client.refunds.create({
260
+ * paymentId: 'pay_abc123',
261
+ * reason: 'Customer request',
262
+ * });
263
+ *
264
+ * // Partial refund
265
+ * const refund = await client.refunds.create({
266
+ * paymentId: 'pay_abc123',
267
+ * amount: 500, // $5.00 in cents
268
+ * reason: 'Partial return',
269
+ * });
270
+ * ```
271
+ */
272
+ async create(params, options) {
273
+ return this.http.post("/refunds", params, options);
274
+ }
275
+ /**
276
+ * Retrieve a refund by ID
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * const refund = await client.refunds.retrieve('ref_abc123');
281
+ * console.log(refund.status);
282
+ * ```
283
+ */
284
+ async retrieve(id, options) {
285
+ return this.http.get(`/refunds/${id}`, options);
286
+ }
287
+ /**
288
+ * List all refunds with optional filters
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * // List all refunds for a payment
293
+ * const { data } = await client.refunds.list({
294
+ * paymentId: 'pay_abc123',
295
+ * });
296
+ *
297
+ * // List refunds by status
298
+ * const { data } = await client.refunds.list({
299
+ * status: 'completed',
300
+ * limit: 20,
301
+ * });
302
+ * ```
303
+ */
304
+ async list(params, options) {
305
+ const searchParams = new URLSearchParams();
306
+ if (params?.limit) searchParams.set("limit", params.limit.toString());
307
+ if (params?.cursor) searchParams.set("cursor", params.cursor);
308
+ if (params?.paymentId) searchParams.set("paymentId", params.paymentId);
309
+ if (params?.status) searchParams.set("status", params.status);
310
+ const query = searchParams.toString();
311
+ const path = query ? `/refunds?${query}` : "/refunds";
312
+ return this.http.get(path, options);
313
+ }
314
+ };
315
+
316
+ // src/resources/customers.ts
317
+ var Customers = class {
318
+ constructor(http) {
319
+ this.http = http;
320
+ }
321
+ /**
322
+ * Create a new customer
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * const customer = await client.customers.create({
327
+ * email: 'john@example.com',
328
+ * firstName: 'John',
329
+ * lastName: 'Doe',
330
+ * metadata: { userId: '12345' },
331
+ * });
332
+ * ```
333
+ */
334
+ async create(params, options) {
335
+ return this.http.post("/customers", params, options);
336
+ }
337
+ /**
338
+ * Retrieve a customer by ID
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * const customer = await client.customers.retrieve('cus_abc123');
343
+ * console.log(customer.email);
344
+ * ```
345
+ */
346
+ async retrieve(id, options) {
347
+ return this.http.get(`/customers/${id}`, options);
348
+ }
349
+ /**
350
+ * Update a customer
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * const customer = await client.customers.update('cus_abc123', {
355
+ * firstName: 'Jane',
356
+ * phone: '+1234567890',
357
+ * });
358
+ * ```
359
+ */
360
+ async update(id, params, options) {
361
+ return this.http.patch(`/customers/${id}`, params, options);
362
+ }
363
+ /**
364
+ * Delete a customer
365
+ *
366
+ * @example
367
+ * ```typescript
368
+ * await client.customers.delete('cus_abc123');
369
+ * ```
370
+ */
371
+ async delete(id, options) {
372
+ await this.http.delete(`/customers/${id}`, options);
373
+ }
374
+ /**
375
+ * List all customers with optional filters
376
+ *
377
+ * @example
378
+ * ```typescript
379
+ * const { data, hasMore } = await client.customers.list({
380
+ * limit: 20,
381
+ * });
382
+ *
383
+ * // Search by email
384
+ * const { data } = await client.customers.list({
385
+ * email: 'john@example.com',
386
+ * });
387
+ * ```
388
+ */
389
+ async list(params, options) {
390
+ const searchParams = new URLSearchParams();
391
+ if (params?.limit) searchParams.set("limit", params.limit.toString());
392
+ if (params?.cursor) searchParams.set("cursor", params.cursor);
393
+ if (params?.email) searchParams.set("email", params.email);
394
+ if (params?.createdAfter) searchParams.set("createdAfter", params.createdAfter);
395
+ if (params?.createdBefore) searchParams.set("createdBefore", params.createdBefore);
396
+ const query = searchParams.toString();
397
+ const path = query ? `/customers?${query}` : "/customers";
398
+ return this.http.get(path, options);
399
+ }
400
+ };
401
+
402
+ // src/resources/subscriptions.ts
403
+ var Subscriptions = class {
404
+ constructor(http) {
405
+ this.http = http;
406
+ }
407
+ /**
408
+ * Create a new subscription
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * const subscription = await client.subscriptions.create({
413
+ * customerId: 'cus_abc123',
414
+ * amount: 2999, // $29.99 in cents
415
+ * currency: 'usd',
416
+ * interval: 'month',
417
+ * });
418
+ * ```
419
+ */
420
+ async create(params, options) {
421
+ return this.http.post("/subscriptions", params, options);
422
+ }
423
+ /**
424
+ * Retrieve a subscription by ID
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * const subscription = await client.subscriptions.retrieve('sub_abc123');
429
+ * console.log(subscription.status);
430
+ * ```
431
+ */
432
+ async retrieve(id, options) {
433
+ return this.http.get(`/subscriptions/${id}`, options);
434
+ }
435
+ /**
436
+ * Cancel a subscription
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * // Cancel immediately
441
+ * const subscription = await client.subscriptions.cancel('sub_abc123');
442
+ *
443
+ * // Cancel at end of billing period
444
+ * const subscription = await client.subscriptions.cancel('sub_abc123', {
445
+ * atPeriodEnd: true,
446
+ * });
447
+ * ```
448
+ */
449
+ async cancel(id, params, options) {
450
+ return this.http.post(
451
+ `/subscriptions/${id}/cancel`,
452
+ params || {},
453
+ options
454
+ );
455
+ }
456
+ /**
457
+ * Pause a subscription
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * const subscription = await client.subscriptions.pause('sub_abc123');
462
+ * ```
463
+ */
464
+ async pause(id, options) {
465
+ return this.http.post(`/subscriptions/${id}/pause`, {}, options);
466
+ }
467
+ /**
468
+ * Resume a paused subscription
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * const subscription = await client.subscriptions.resume('sub_abc123');
473
+ * ```
474
+ */
475
+ async resume(id, options) {
476
+ return this.http.post(`/subscriptions/${id}/resume`, {}, options);
477
+ }
478
+ /**
479
+ * List all subscriptions with optional filters
480
+ *
481
+ * @example
482
+ * ```typescript
483
+ * // List all active subscriptions
484
+ * const { data } = await client.subscriptions.list({
485
+ * status: 'active',
486
+ * });
487
+ *
488
+ * // List subscriptions for a customer
489
+ * const { data } = await client.subscriptions.list({
490
+ * customerId: 'cus_abc123',
491
+ * });
492
+ * ```
493
+ */
494
+ async list(params, options) {
495
+ const searchParams = new URLSearchParams();
496
+ if (params?.limit) searchParams.set("limit", params.limit.toString());
497
+ if (params?.cursor) searchParams.set("cursor", params.cursor);
498
+ if (params?.customerId) searchParams.set("customerId", params.customerId);
499
+ if (params?.status) searchParams.set("status", params.status);
500
+ const query = searchParams.toString();
501
+ const path = query ? `/subscriptions?${query}` : "/subscriptions";
502
+ return this.http.get(path, options);
503
+ }
504
+ };
505
+
506
+ // src/resources/webhooks.ts
507
+ var Webhooks = class {
508
+ /**
509
+ * Verify webhook signature and parse the event
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * // Express.js example
514
+ * app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
515
+ * const signature = req.headers['imerchant-signature'] as string;
516
+ *
517
+ * try {
518
+ * const event = iMerchant.webhooks.verify({
519
+ * body: req.body.toString(),
520
+ * signature,
521
+ * }, process.env.WEBHOOK_SECRET);
522
+ *
523
+ * switch (event.type) {
524
+ * case 'payment.captured':
525
+ * // Handle successful payment
526
+ * break;
527
+ * case 'payment.failed':
528
+ * // Handle failed payment
529
+ * break;
530
+ * }
531
+ *
532
+ * res.json({ received: true });
533
+ * } catch (err) {
534
+ * res.status(400).send('Invalid signature');
535
+ * }
536
+ * });
537
+ * ```
538
+ *
539
+ * @param payload - The webhook payload containing body and signature
540
+ * @param secret - Your webhook signing secret
541
+ * @returns The verified and parsed webhook event
542
+ * @throws {WebhookSignatureError} If signature verification fails
543
+ */
544
+ static verify(payload, secret) {
545
+ if (!payload.body || !payload.signature) {
546
+ throw new WebhookSignatureError("Missing payload body or signature");
547
+ }
548
+ if (!secret) {
549
+ throw new WebhookSignatureError("Webhook secret is required");
550
+ }
551
+ const parts = payload.signature.split(",");
552
+ const signatureParts = {};
553
+ for (const part of parts) {
554
+ const [key, value] = part.split("=");
555
+ if (key && value) {
556
+ signatureParts[key] = value;
557
+ }
558
+ }
559
+ const timestamp = signatureParts["t"];
560
+ const signature = signatureParts["v1"];
561
+ if (!timestamp || !signature) {
562
+ throw new WebhookSignatureError("Invalid signature format");
563
+ }
564
+ const timestampAge = Date.now() - parseInt(timestamp, 10) * 1e3;
565
+ if (timestampAge > 5 * 60 * 1e3) {
566
+ throw new WebhookSignatureError("Webhook timestamp too old");
567
+ }
568
+ const expectedSignature = this.computeSignature(
569
+ `${timestamp}.${payload.body}`,
570
+ secret
571
+ );
572
+ if (!this.secureCompare(signature, expectedSignature)) {
573
+ throw new WebhookSignatureError("Signature verification failed");
574
+ }
575
+ try {
576
+ return JSON.parse(payload.body);
577
+ } catch {
578
+ throw new WebhookSignatureError("Invalid JSON payload");
579
+ }
580
+ }
581
+ /**
582
+ * Compute HMAC-SHA256 signature
583
+ * Uses Node.js crypto module (available in Node.js environments)
584
+ */
585
+ static computeSignature(data, secret) {
586
+ if (typeof process !== "undefined" && process.versions?.node) {
587
+ try {
588
+ const requireFn = new Function("moduleName", "return require(moduleName)");
589
+ const cryptoModule = requireFn("crypto");
590
+ return cryptoModule.createHmac("sha256", secret).update(data).digest("hex");
591
+ } catch {
592
+ throw new WebhookSignatureError(
593
+ "Unable to load crypto module. Ensure you are running in Node.js."
594
+ );
595
+ }
596
+ }
597
+ throw new WebhookSignatureError(
598
+ "Synchronous signature verification is only available in Node.js. Use verifyAsync() in browser environments."
599
+ );
600
+ }
601
+ /**
602
+ * Timing-safe string comparison to prevent timing attacks
603
+ */
604
+ static secureCompare(a, b) {
605
+ if (a.length !== b.length) {
606
+ return false;
607
+ }
608
+ let result = 0;
609
+ for (let i = 0; i < a.length; i++) {
610
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
611
+ }
612
+ return result === 0;
613
+ }
614
+ /**
615
+ * Async signature verification using Web Crypto API
616
+ * Use this in environments that support Web Crypto
617
+ *
618
+ * @example
619
+ * ```typescript
620
+ * const event = await iMerchant.webhooks.verifyAsync(payload, secret);
621
+ * ```
622
+ */
623
+ static async verifyAsync(payload, secret) {
624
+ if (!payload.body || !payload.signature) {
625
+ throw new WebhookSignatureError("Missing payload body or signature");
626
+ }
627
+ if (!secret) {
628
+ throw new WebhookSignatureError("Webhook secret is required");
629
+ }
630
+ const parts = payload.signature.split(",");
631
+ const signatureParts = {};
632
+ for (const part of parts) {
633
+ const [key2, value] = part.split("=");
634
+ if (key2 && value) {
635
+ signatureParts[key2] = value;
636
+ }
637
+ }
638
+ const timestamp = signatureParts["t"];
639
+ const signature = signatureParts["v1"];
640
+ if (!timestamp || !signature) {
641
+ throw new WebhookSignatureError("Invalid signature format");
642
+ }
643
+ const timestampAge = Date.now() - parseInt(timestamp, 10) * 1e3;
644
+ if (timestampAge > 5 * 60 * 1e3) {
645
+ throw new WebhookSignatureError("Webhook timestamp too old");
646
+ }
647
+ const encoder = new TextEncoder();
648
+ const key = await crypto.subtle.importKey(
649
+ "raw",
650
+ encoder.encode(secret),
651
+ { name: "HMAC", hash: "SHA-256" },
652
+ false,
653
+ ["sign"]
654
+ );
655
+ const signatureData = encoder.encode(`${timestamp}.${payload.body}`);
656
+ const signatureBuffer = await crypto.subtle.sign("HMAC", key, signatureData);
657
+ const expectedSignature = Array.from(new Uint8Array(signatureBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
658
+ if (!this.secureCompare(signature, expectedSignature)) {
659
+ throw new WebhookSignatureError("Signature verification failed");
660
+ }
661
+ try {
662
+ return JSON.parse(payload.body);
663
+ } catch {
664
+ throw new WebhookSignatureError("Invalid JSON payload");
665
+ }
666
+ }
667
+ };
668
+
669
+ // src/client.ts
670
+ var iMerchant = class {
671
+ /**
672
+ * Create a new iMerchant client
673
+ *
674
+ * @param config - Client configuration
675
+ * @param config.apiKey - Your iMerchant API key (required)
676
+ * @param config.baseUrl - API base URL (optional, defaults to https://api.imerchant.com)
677
+ * @param config.timeout - Request timeout in ms (optional, defaults to 30000)
678
+ * @param config.apiVersion - API version (optional, defaults to 'v1')
679
+ */
680
+ constructor(config) {
681
+ this.http = new HttpClient(config);
682
+ this.payments = new Payments(this.http);
683
+ this.refunds = new Refunds(this.http);
684
+ this.customers = new Customers(this.http);
685
+ this.subscriptions = new Subscriptions(this.http);
686
+ }
687
+ };
688
+ /**
689
+ * Static webhook utilities for signature verification
690
+ */
691
+ iMerchant.webhooks = Webhooks;
692
+ export {
693
+ APIError,
694
+ AuthenticationError,
695
+ Customers,
696
+ NotFoundError,
697
+ Payments,
698
+ RateLimitError,
699
+ Refunds,
700
+ Subscriptions,
701
+ ValidationError,
702
+ WebhookSignatureError,
703
+ Webhooks,
704
+ iMerchant,
705
+ iMerchantError
706
+ };