@toneflix/paystack-cli 0.1.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.
Files changed (5) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +907 -0
  3. package/bin/cli.cjs +3277 -0
  4. package/bin/cli.js +3248 -0
  5. package/package.json +81 -0
package/bin/cli.cjs ADDED
@@ -0,0 +1,3277 @@
1
+ #!/usr/bin/env node
2
+ //#region rolldown:runtime
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+
24
+ //#endregion
25
+ let better_sqlite3 = require("better-sqlite3");
26
+ better_sqlite3 = __toESM(better_sqlite3);
27
+ let __h3ravel_shared = require("@h3ravel/shared");
28
+ __h3ravel_shared = __toESM(__h3ravel_shared);
29
+ let axios = require("axios");
30
+ axios = __toESM(axios);
31
+ let __h3ravel_musket = require("@h3ravel/musket");
32
+ __h3ravel_musket = __toESM(__h3ravel_musket);
33
+ let ora = require("ora");
34
+ ora = __toESM(ora);
35
+ let crypto = require("crypto");
36
+ crypto = __toESM(crypto);
37
+ let __ngrok_ngrok = require("@ngrok/ngrok");
38
+ __ngrok_ngrok = __toESM(__ngrok_ngrok);
39
+
40
+ //#region src/db.ts
41
+ const db = new better_sqlite3.default("app.db");
42
+ db.pragma("journal_mode = WAL");
43
+ function init(table = "json_store") {
44
+ return db.exec(`
45
+ CREATE TABLE IF NOT EXISTS ${table} (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ key TEXT UNIQUE,
48
+ value TEXT
49
+ )
50
+ `);
51
+ }
52
+ /**
53
+ * Save a value to the database
54
+ *
55
+ * @param key
56
+ * @param value
57
+ * @returns
58
+ */
59
+ function write(key, value, table = "json_store") {
60
+ if (typeof value === "boolean") value = value ? "1" : "0";
61
+ if (value instanceof Object) value = JSON.stringify(value);
62
+ return db.prepare(`INSERT INTO ${table} (key, value)
63
+ VALUES (?, ?)
64
+ ON CONFLICT(key) DO UPDATE SET value=excluded.value
65
+ `).run(key, value).lastInsertRowid;
66
+ }
67
+ function remove(key, table = "json_store") {
68
+ return db.prepare(`DELETE FROM ${table} WHERE key = ?`).run(key).lastInsertRowid;
69
+ }
70
+ /**
71
+ * Read a value from the database
72
+ *
73
+ * @param key
74
+ * @returns
75
+ */
76
+ function read(key, table = "json_store") {
77
+ const row = db.prepare(`SELECT * FROM ${table} WHERE key = ?`).get(key);
78
+ if (row) try {
79
+ return JSON.parse(row.value);
80
+ } catch {
81
+ return row.value;
82
+ }
83
+ return null;
84
+ }
85
+
86
+ //#endregion
87
+ //#region src/hooks.ts
88
+ let commandInstance;
89
+ /**
90
+ * Hook to get or set the current Command instance.
91
+ */
92
+ function useCommand() {
93
+ return [() => {
94
+ if (!commandInstance) throw new Error("Commander instance has not been initialized");
95
+ return commandInstance;
96
+ }, (newCommand) => {
97
+ commandInstance = newCommand;
98
+ }];
99
+ }
100
+ /**
101
+ * Hook to get or set the application configuration.
102
+ *
103
+ * @returns
104
+ */
105
+ function useConfig() {
106
+ return [() => {
107
+ return read("config") || {
108
+ debug: false,
109
+ apiBaseURL: "https://api.paystack.co",
110
+ timeoutDuration: 3e3
111
+ };
112
+ }, (config) => {
113
+ write("config", config);
114
+ return read("config");
115
+ }];
116
+ }
117
+ const shortcutUsed = /* @__PURE__ */ new Set();
118
+ /**
119
+ * Hook to make command shortcuts unique across the application.
120
+ *
121
+ * @returns
122
+ */
123
+ function useShortcuts() {
124
+ return [() => Array.from(shortcutUsed).filter((s) => !!s), (shortcut) => {
125
+ if (!shortcut) {
126
+ shortcutUsed.clear();
127
+ return false;
128
+ }
129
+ if (shortcutUsed.has(shortcut)) return false;
130
+ shortcutUsed.add(shortcut);
131
+ return true;
132
+ }];
133
+ }
134
+
135
+ //#endregion
136
+ //#region src/axios.ts
137
+ const api = axios.default.create({
138
+ baseURL: "https://api.paystack.co",
139
+ headers: { "Content-Type": "application/json" }
140
+ });
141
+ /**
142
+ * Initialize Axios with configuration from the application settings.
143
+ */
144
+ const initAxios = () => {
145
+ const [getConfig] = useConfig();
146
+ const config = getConfig();
147
+ api.defaults.baseURL = config.apiBaseURL || "https://api.paystack.co";
148
+ api.defaults.timeout = config.timeoutDuration || 3e3;
149
+ };
150
+ /**
151
+ * Log the full request details if we are not in production
152
+ * @param config
153
+ * @returns
154
+ */
155
+ const logInterceptor = (config) => {
156
+ const [getConfig] = useConfig();
157
+ const [command] = useCommand();
158
+ const conf = getConfig();
159
+ const v = command().getVerbosity();
160
+ if (conf.debug || v > 1) {
161
+ console.log("Error Response URL:", axios.default.getUri(config));
162
+ if (conf.debug || v >= 2) {
163
+ console.log("Request URL:", config.url);
164
+ console.log("Request Method:", config.method);
165
+ }
166
+ if (conf.debug || v == 3) {
167
+ console.log("Request Headers:", config.headers);
168
+ console.log("Request Data:", config.data);
169
+ }
170
+ }
171
+ return config;
172
+ };
173
+ /**
174
+ * Log only the relevant parts of the response if we are in not in production
175
+ *
176
+ * @param response
177
+ * @returns
178
+ */
179
+ const logResponseInterceptor = (response) => {
180
+ const [getConfig] = useConfig();
181
+ const [command] = useCommand();
182
+ const conf = getConfig();
183
+ const v = command().getVerbosity();
184
+ if (conf.debug || v > 1) {
185
+ const { data, status, statusText, headers } = response;
186
+ console.log("Error Response URL:", axios.default.getUri(response.config));
187
+ if (conf.debug || v >= 2) {
188
+ console.log("Response Data:", data);
189
+ console.log("Response Status:", status);
190
+ }
191
+ if (conf.debug || v === 3) {
192
+ console.log("Response Status Text:", statusText);
193
+ console.log("Response Headers:", headers);
194
+ }
195
+ }
196
+ return response;
197
+ };
198
+ const logResponseErrorInterceptor = (error) => {
199
+ const [getConfig] = useConfig();
200
+ const [command] = useCommand();
201
+ const conf = getConfig();
202
+ const v = command().getVerbosity();
203
+ if (conf.debug || v > 1) if (error.response) {
204
+ const { data, status, headers } = error.response;
205
+ console.log("Error Response URL:", axios.default.getUri(error.config));
206
+ if (conf.debug || v >= 2) {
207
+ console.log("Error Response Data:", data);
208
+ console.log("Error Response Status:", status);
209
+ }
210
+ if (conf.debug || v === 3) console.log("Error Response Headers:", headers);
211
+ } else console.log("Error Message:", error.message);
212
+ return Promise.reject(error);
213
+ };
214
+ api.interceptors.request.use(logInterceptor, (error) => Promise.reject(error));
215
+ api.interceptors.response.use(logResponseInterceptor, logResponseErrorInterceptor);
216
+ var axios_default = api;
217
+
218
+ //#endregion
219
+ //#region src/helpers.ts
220
+ const promiseWrapper = (promise) => promise.then((data) => [null, data]).catch((error) => [typeof error === "string" ? error : error.message, null]);
221
+ function isJson(val) {
222
+ return val instanceof Array || val instanceof Object ? true : false;
223
+ }
224
+ function parseURL(uri) {
225
+ if (!uri.startsWith("http")) uri = "http://" + uri;
226
+ return new URL(uri);
227
+ }
228
+ function getKeys$1(token, type = "secret", domain = "test") {
229
+ return new Promise((resolve, reject) => {
230
+ axios_default.get("/integration/keys", { headers: {
231
+ Authorization: "Bearer " + token,
232
+ "jwt-auth": true
233
+ } }).then((response) => {
234
+ let key = {};
235
+ const keys = response.data.data;
236
+ if (keys.length) {
237
+ for (let i = 0; i < keys.length; i++) if (keys[i].domain === domain && keys[i].type === type) {
238
+ key = keys[i];
239
+ break;
240
+ }
241
+ }
242
+ resolve(key.key);
243
+ }).catch((error) => {
244
+ if (error.response) {
245
+ reject(error.response.data.message);
246
+ return;
247
+ }
248
+ reject(error);
249
+ });
250
+ });
251
+ }
252
+ async function executeSchema(schema, options) {
253
+ let domain = "test";
254
+ if (options.domain) domain = options.domain;
255
+ const key = await getKeys$1(read("token"), "secret", domain);
256
+ const [getConfig] = useConfig();
257
+ const config = getConfig();
258
+ return new Promise((resolve, reject) => {
259
+ let params = {}, data = {};
260
+ if (schema.method == "GET") params = options;
261
+ if (schema.method == "POST") data = options;
262
+ const pathVars = [...schema.endpoint.matchAll(/\{([^}]+)\}/g)].map((match) => match[1]);
263
+ if (pathVars.length >= 0) for (const path of pathVars) schema.endpoint = schema.endpoint.replace("{" + path + "}", options[path]);
264
+ const url = new URL(schema.endpoint, config.apiBaseURL || "https://api.paystack.co");
265
+ params = {
266
+ ...params,
267
+ ...Object.fromEntries(url.searchParams.entries())
268
+ };
269
+ axios_default.request({
270
+ url: url.pathname,
271
+ method: schema.method,
272
+ params,
273
+ data,
274
+ timeout: config.timeoutDuration || 0,
275
+ headers: { Authorization: "Bearer " + key }
276
+ }).then(({ data: data$1 }) => {
277
+ resolve(data$1);
278
+ }).catch((err) => {
279
+ reject(err.response?.data?.message ?? err.response?.message ?? err.message ?? err.statusText);
280
+ });
281
+ });
282
+ }
283
+ const wait = (ms, callback) => {
284
+ return new Promise((resolve) => {
285
+ setTimeout(() => {
286
+ if (callback) resolve(callback());
287
+ resolve();
288
+ }, ms);
289
+ });
290
+ };
291
+ const logger = (str, config = ["green", "italic"]) => {
292
+ return __h3ravel_shared.Logger.log(str, config, false);
293
+ };
294
+
295
+ //#endregion
296
+ //#region src/paystack/apis.ts
297
+ const APIs = {
298
+ subaccount: [
299
+ {
300
+ api: "update",
301
+ endpoint: "https://api.paystack.co/subaccount",
302
+ method: "PUT",
303
+ params: [],
304
+ description: "Update a subaccount"
305
+ },
306
+ {
307
+ api: "fetch",
308
+ endpoint: "https://api.paystack.co/subaccount/{id}",
309
+ method: "GET",
310
+ params: [{
311
+ parameter: "id",
312
+ required: true,
313
+ type: "String",
314
+ description: "The ID of the subaccount to fetch",
315
+ paramType: "path"
316
+ }],
317
+ description: "Fetch a specific subaccount"
318
+ },
319
+ {
320
+ api: "list",
321
+ endpoint: "https://api.paystack.co/subaccount",
322
+ method: "GET",
323
+ params: [{
324
+ parameter: "perPage",
325
+ required: false,
326
+ type: "String",
327
+ description: "Specify how many records you want to retrieve per page"
328
+ }, {
329
+ parameter: "page",
330
+ required: false,
331
+ type: "Number",
332
+ description: "Specify exactly what page you want to retrieve"
333
+ }],
334
+ description: "List all sub accounts created on your integration "
335
+ },
336
+ {
337
+ api: "create",
338
+ endpoint: "https://api.paystack.co/subaccount",
339
+ method: "POST",
340
+ params: [
341
+ {
342
+ parameter: "business_name",
343
+ required: true,
344
+ type: "String",
345
+ description: "Name of business for subaccount"
346
+ },
347
+ {
348
+ parameter: "settlement_bank",
349
+ required: true,
350
+ type: "String",
351
+ description: "Bank code (see List Banks endpoint for accepted codes)"
352
+ },
353
+ {
354
+ parameter: "account_number",
355
+ required: true,
356
+ type: "String",
357
+ description: "NUBAN bank account number"
358
+ },
359
+ {
360
+ parameter: "percentage_charge",
361
+ required: true,
362
+ type: "String",
363
+ description: "Default percentage charged when receiving on behalf of this subaccount"
364
+ },
365
+ {
366
+ parameter: "primary_contact_email",
367
+ required: false,
368
+ type: "String",
369
+ description: "Contact email for the subaccount"
370
+ },
371
+ {
372
+ parameter: "primary_contact_name",
373
+ required: false,
374
+ type: "String",
375
+ description: "Contact person name for this subaccount"
376
+ },
377
+ {
378
+ parameter: "primary_contact_phone",
379
+ required: false,
380
+ type: "String",
381
+ description: "Contact phone number for this subaccount"
382
+ },
383
+ {
384
+ parameter: "metadata",
385
+ required: false,
386
+ type: "String",
387
+ description: "Additional information in structured JSON format"
388
+ },
389
+ {
390
+ parameter: "settlement_schedule",
391
+ required: false,
392
+ type: "String",
393
+ description: "Settlement schedule: \"auto\" (T+1), \"weekly\", \"monthly\", or \"manual\""
394
+ }
395
+ ],
396
+ description: "Create a new subaccount"
397
+ }
398
+ ],
399
+ page: [
400
+ {
401
+ api: "update",
402
+ endpoint: "https://api.paystack.co/page/",
403
+ method: "PUT",
404
+ params: [
405
+ {
406
+ parameter: "name",
407
+ required: false,
408
+ type: "String",
409
+ description: "Name of page"
410
+ },
411
+ {
412
+ parameter: "description",
413
+ required: false,
414
+ type: "String",
415
+ description: "Short description of page"
416
+ },
417
+ {
418
+ parameter: "amount",
419
+ required: false,
420
+ type: "Number",
421
+ description: "Amount to be charged in kobo. Will override the amount for existing subscriptions"
422
+ },
423
+ {
424
+ parameter: "active",
425
+ required: false,
426
+ type: "String",
427
+ description: "Set to false to deactivate page url"
428
+ }
429
+ ],
430
+ description: "Update a payment page"
431
+ },
432
+ {
433
+ api: "fetch",
434
+ endpoint: "https://api.paystack.co/page/id_or_plan_code",
435
+ method: "GET",
436
+ params: [],
437
+ description: "Fetch a specific payment page"
438
+ },
439
+ {
440
+ api: "list",
441
+ endpoint: "https://api.paystack.co/page",
442
+ method: "GET",
443
+ params: [
444
+ {
445
+ parameter: "perPage",
446
+ required: false,
447
+ type: "String",
448
+ description: "Specify how many records you want to retrieve per page"
449
+ },
450
+ {
451
+ parameter: "page",
452
+ required: false,
453
+ type: "Number",
454
+ description: "Specify exactly what page you want to retrieve"
455
+ },
456
+ {
457
+ parameter: "interval",
458
+ required: false,
459
+ type: "String",
460
+ description: "Filter list by plans with specified interval"
461
+ },
462
+ {
463
+ parameter: "amount",
464
+ required: false,
465
+ type: "Number",
466
+ description: "Filter list by plans with specified amount (in kobo)"
467
+ }
468
+ ],
469
+ description: "List all payment pages"
470
+ },
471
+ {
472
+ api: "check",
473
+ endpoint: "https://api.paystack.co/page/check_slug_availability/slug",
474
+ method: "GET",
475
+ params: [{
476
+ parameter: "slug",
477
+ required: true,
478
+ type: "String",
479
+ description: "URL slug to be confirmed"
480
+ }],
481
+ description: "Check if a page slug is available"
482
+ },
483
+ {
484
+ api: "create",
485
+ endpoint: "https://api.paystack.co/page",
486
+ method: "POST",
487
+ params: [
488
+ {
489
+ parameter: "name",
490
+ required: true,
491
+ type: "String",
492
+ description: "Name of page"
493
+ },
494
+ {
495
+ parameter: "description",
496
+ required: false,
497
+ type: "String",
498
+ description: "Short description of page"
499
+ },
500
+ {
501
+ parameter: "amount",
502
+ required: false,
503
+ type: "Number",
504
+ description: "Default amount to accept using this page (leave empty for donations)"
505
+ },
506
+ {
507
+ parameter: "slug",
508
+ required: false,
509
+ type: "String",
510
+ description: "URL slug for the page (page will be accessible at https://paystack.com/pay/[slug])"
511
+ },
512
+ {
513
+ parameter: "redirect_url",
514
+ required: false,
515
+ type: "String",
516
+ description: "URL to redirect to upon successful payment"
517
+ },
518
+ {
519
+ parameter: "send_invoices",
520
+ required: false,
521
+ type: "String",
522
+ description: "Set to false to disable invoice emails"
523
+ },
524
+ {
525
+ parameter: "custom_fields",
526
+ required: false,
527
+ type: "String",
528
+ description: "Custom fields to accept (see documentation for format)"
529
+ }
530
+ ],
531
+ description: "Create a new payment page"
532
+ }
533
+ ],
534
+ transfer: [
535
+ {
536
+ api: "list",
537
+ endpoint: "https://api.paystack.co/transfer",
538
+ method: "GET",
539
+ params: [{
540
+ parameter: "perPage",
541
+ required: false,
542
+ type: "String",
543
+ description: "Specify how many records you want to retrieve per page"
544
+ }, {
545
+ parameter: "page",
546
+ required: false,
547
+ type: "Number",
548
+ description: "Specify exactly what page you want to retrieve"
549
+ }],
550
+ description: "List all transfers"
551
+ },
552
+ {
553
+ api: "finalize",
554
+ endpoint: "https://api.paystack.co/transfer/finalize_transfer",
555
+ method: "POST",
556
+ params: [{
557
+ parameter: "transfer_code",
558
+ required: true,
559
+ type: "String",
560
+ description: "Transfer code"
561
+ }, {
562
+ parameter: "otp",
563
+ required: true,
564
+ type: "String",
565
+ description: "OTP sent to business phone to verify transfer"
566
+ }],
567
+ description: "Finalize a transfer by confirming OTP"
568
+ },
569
+ {
570
+ api: "initiate",
571
+ endpoint: "https://api.paystack.co/transfer",
572
+ method: "POST",
573
+ params: [
574
+ {
575
+ parameter: "source",
576
+ required: true,
577
+ type: "String",
578
+ description: "Where should we transfer from? Only [balance] for now"
579
+ },
580
+ {
581
+ parameter: "amount",
582
+ required: false,
583
+ type: "Number",
584
+ description: "Amount to transfer in kobo"
585
+ },
586
+ {
587
+ parameter: "currency",
588
+ required: false,
589
+ type: "String",
590
+ description: "Specify the currency of the transfer. Defaults to NGN",
591
+ default: "NGN",
592
+ options: [
593
+ "NGN",
594
+ "GHS",
595
+ "ZAR",
596
+ "KES",
597
+ "UGX",
598
+ "TZS",
599
+ "XAF",
600
+ "XOF",
601
+ "USD"
602
+ ]
603
+ },
604
+ {
605
+ parameter: "reason",
606
+ required: false,
607
+ type: "String",
608
+ description: "The reason for the transfer."
609
+ },
610
+ {
611
+ parameter: "recipient",
612
+ required: true,
613
+ type: "String",
614
+ description: "Code for transfer recipient."
615
+ },
616
+ {
617
+ parameter: "reference",
618
+ required: false,
619
+ type: "String",
620
+ description: "If specified, the field should be a unique identifier (in lowercase) for the object. Only `-` `,` `_` and alphanumeric characters allowed."
621
+ },
622
+ {
623
+ parameter: "account_reference",
624
+ required: false,
625
+ type: "String",
626
+ description: "A unique identifier required in Kenya for MPESA Paybill and Till transfers."
627
+ }
628
+ ],
629
+ description: "Send money to your customers. Status of transfer object returned will be [pending] if OTP is disabled. In the event that an OTP is required, status will read [otp]."
630
+ },
631
+ {
632
+ api: "verify",
633
+ endpoint: "https://api.paystack.co/transfer/{reference}",
634
+ method: "GET",
635
+ params: [
636
+ {
637
+ parameter: "perPage",
638
+ required: false,
639
+ type: "String",
640
+ description: "Specify how many records you want to retrieve per page"
641
+ },
642
+ {
643
+ parameter: "page",
644
+ required: false,
645
+ type: "Number",
646
+ description: "Specify exactly what page you want to retrieve"
647
+ },
648
+ {
649
+ parameter: "reference",
650
+ required: true,
651
+ type: "String",
652
+ description: "Transfer reference to verify",
653
+ paramType: "path"
654
+ }
655
+ ],
656
+ description: "Verify transfer status by reference"
657
+ },
658
+ {
659
+ api: "disable",
660
+ endpoint: "https://api.paystack.co/transfer/disable_otp",
661
+ method: "POST",
662
+ params: [],
663
+ description: "Disable OTP requirement for transfers"
664
+ },
665
+ {
666
+ api: "enable",
667
+ endpoint: "https://api.paystack.co/transfer/enable_otp",
668
+ method: "POST",
669
+ params: [],
670
+ description: "Enable OTP requirement for transfers"
671
+ },
672
+ {
673
+ api: "initiate",
674
+ endpoint: "https://api.paystack.co/transfer/bulk",
675
+ method: "POST",
676
+ params: [{
677
+ parameter: "source",
678
+ required: false,
679
+ type: "String",
680
+ description: "Where should we transfer from? Only [balance] for now"
681
+ }, {
682
+ parameter: "transfers",
683
+ required: true,
684
+ type: "Array",
685
+ description: "A list of transfer object.."
686
+ }],
687
+ description: "Batch multiple transfers in a single request. You need to disable the Transfers OTP requirement to use this endpoint."
688
+ },
689
+ {
690
+ api: "finalize",
691
+ endpoint: "https://api.paystack.co/transfer/disable_otp_finalize",
692
+ method: "POST",
693
+ params: [{
694
+ parameter: "otp",
695
+ required: true,
696
+ type: "String",
697
+ description: "OTP sent to business phone to verify disabling OTP requirement"
698
+ }],
699
+ description: "Finalize disabling OTP with confirmation code"
700
+ },
701
+ {
702
+ api: "fetch",
703
+ endpoint: "https://api.paystack.co/transfer/id",
704
+ method: "GET",
705
+ params: [{
706
+ parameter: "id_or_code",
707
+ required: true,
708
+ type: "String",
709
+ description: "An ID or code for the transfer to retrieve"
710
+ }],
711
+ description: "Fetch transfer details by ID or code"
712
+ },
713
+ {
714
+ api: "list",
715
+ endpoint: "https://api.paystack.co/transfer/id_or_code",
716
+ method: "GET",
717
+ params: [{
718
+ parameter: "perPage",
719
+ required: false,
720
+ type: "String",
721
+ description: "Specify how many records you want to retrieve per page"
722
+ }, {
723
+ parameter: "page",
724
+ required: false,
725
+ type: "Number",
726
+ description: "Specify exactly what page you want to retrieve"
727
+ }],
728
+ description: "List all bulk charge batches"
729
+ },
730
+ {
731
+ api: "resend",
732
+ endpoint: "https://api.paystack.co/transfer/resend_otp",
733
+ method: "POST",
734
+ params: [{
735
+ parameter: "transfer_code",
736
+ required: true,
737
+ type: "String",
738
+ description: "Transfer code"
739
+ }, {
740
+ parameter: "reason",
741
+ required: true,
742
+ type: "String",
743
+ description: "Either \"resend_otp\" or \"transfer\""
744
+ }],
745
+ description: "Resend OTP for a transfer"
746
+ }
747
+ ],
748
+ paymentrequest: [
749
+ {
750
+ api: "create",
751
+ endpoint: "https://api.paystack.co/paymentrequest",
752
+ method: "POST",
753
+ params: [
754
+ {
755
+ parameter: "customer",
756
+ required: true,
757
+ type: "String",
758
+ description: "Customer ID or code"
759
+ },
760
+ {
761
+ parameter: "due_date",
762
+ required: true,
763
+ type: "String",
764
+ description: "ISO 8601 representation of request due date"
765
+ },
766
+ {
767
+ parameter: "amount",
768
+ required: true,
769
+ type: "Number",
770
+ description: "Invoice amount in kobo"
771
+ },
772
+ {
773
+ parameter: "description",
774
+ required: false,
775
+ type: "String",
776
+ description: "Description of the payment request"
777
+ },
778
+ {
779
+ parameter: "line_items",
780
+ required: false,
781
+ type: "String",
782
+ description: "Array of line items"
783
+ },
784
+ {
785
+ parameter: "tax",
786
+ required: false,
787
+ type: "String",
788
+ description: "Array of taxes to be charged"
789
+ },
790
+ {
791
+ parameter: "currency",
792
+ required: false,
793
+ type: "String",
794
+ description: "Currency (defaults to NGN)",
795
+ options: [
796
+ "NGN",
797
+ "GHS",
798
+ "ZAR",
799
+ "KES",
800
+ "UGX",
801
+ "TZS",
802
+ "XAF",
803
+ "XOF",
804
+ "USD"
805
+ ]
806
+ },
807
+ {
808
+ parameter: "send_notification",
809
+ required: false,
810
+ type: "String",
811
+ description: "Whether to send email notification (defaults to true)"
812
+ },
813
+ {
814
+ parameter: "draft",
815
+ required: false,
816
+ type: "String",
817
+ description: "Save as draft (defaults to false)"
818
+ },
819
+ {
820
+ parameter: "has_invoice",
821
+ required: false,
822
+ type: "String",
823
+ description: "Create a draft invoice even without line items or tax"
824
+ },
825
+ {
826
+ parameter: "invoice_number",
827
+ required: false,
828
+ type: "String",
829
+ description: "Override the auto-incrementing invoice number"
830
+ }
831
+ ],
832
+ description: "Create a new payment request"
833
+ },
834
+ {
835
+ api: "finalize",
836
+ endpoint: "https://api.paystack.co/paymentrequest/finalize/ID_OR_CODE",
837
+ method: "POST",
838
+ params: [{
839
+ parameter: "send_notification",
840
+ required: false,
841
+ type: "String",
842
+ description: "Whether to send email notification (defaults to true)"
843
+ }],
844
+ description: "Finalize/publish a draft payment request"
845
+ },
846
+ {
847
+ api: "send",
848
+ endpoint: "https://api.paystack.co/paymentrequest/notify/ID_OR_CODE",
849
+ method: "POST",
850
+ params: [],
851
+ description: "Send payment request notification to customer"
852
+ },
853
+ {
854
+ api: "list",
855
+ endpoint: "https://api.paystack.co/paymentrequest",
856
+ method: "GET",
857
+ params: [
858
+ {
859
+ parameter: "customer",
860
+ required: false,
861
+ type: "String",
862
+ description: "Filter by customer ID"
863
+ },
864
+ {
865
+ parameter: "status",
866
+ required: false,
867
+ type: "String",
868
+ description: "Filter by status: \"failed\", \"success\", or \"abandoned\""
869
+ },
870
+ {
871
+ parameter: "currency",
872
+ required: false,
873
+ type: "String",
874
+ description: "Filter by currency",
875
+ options: [
876
+ "NGN",
877
+ "GHS",
878
+ "ZAR",
879
+ "KES",
880
+ "UGX",
881
+ "TZS",
882
+ "XAF",
883
+ "XOF",
884
+ "USD"
885
+ ]
886
+ },
887
+ {
888
+ parameter: "paid",
889
+ required: false,
890
+ type: "String",
891
+ description: "Filter requests that have been paid for"
892
+ },
893
+ {
894
+ parameter: "include_archive",
895
+ required: false,
896
+ type: "String",
897
+ description: "Include archived payment requests"
898
+ },
899
+ {
900
+ parameter: "payment_request",
901
+ required: false,
902
+ type: "String",
903
+ description: "Filter by invoice code"
904
+ }
905
+ ],
906
+ description: "List all payment requests"
907
+ },
908
+ {
909
+ api: "view",
910
+ endpoint: "https://api.paystack.co/paymentrequest/REQUEST_ID_OR_CODE",
911
+ method: "GET",
912
+ params: [{
913
+ parameter: "id",
914
+ required: true,
915
+ type: "String",
916
+ description: "Payment request ID or code"
917
+ }],
918
+ description: "View a specific payment request"
919
+ },
920
+ {
921
+ api: "invoice",
922
+ endpoint: "https://api.paystack.co/paymentrequest/totals",
923
+ method: "GET",
924
+ params: [],
925
+ description: "Get payment request totals"
926
+ },
927
+ {
928
+ api: "update",
929
+ endpoint: "https://api.paystack.co/paymentrequest/ID_OR_CODE",
930
+ method: "PUT",
931
+ params: [
932
+ {
933
+ parameter: "description",
934
+ required: false,
935
+ type: "String",
936
+ description: "Payment request description"
937
+ },
938
+ {
939
+ parameter: "amount",
940
+ required: false,
941
+ type: "Number",
942
+ description: "Amount in kobo"
943
+ },
944
+ {
945
+ parameter: "line_item",
946
+ required: false,
947
+ type: "String",
948
+ description: "Line items"
949
+ },
950
+ {
951
+ parameter: "tax",
952
+ required: false,
953
+ type: "String",
954
+ description: "Taxes"
955
+ },
956
+ {
957
+ parameter: "due_date",
958
+ required: false,
959
+ type: "String",
960
+ description: "Due date for the request"
961
+ },
962
+ {
963
+ parameter: "metadata",
964
+ required: false,
965
+ type: "String",
966
+ description: "Additional metadata"
967
+ },
968
+ {
969
+ parameter: "send_notification",
970
+ required: false,
971
+ type: "String",
972
+ description: "Whether to send notification"
973
+ },
974
+ {
975
+ parameter: "currency",
976
+ required: false,
977
+ type: "String",
978
+ description: "Currency (only works in draft mode)",
979
+ options: [
980
+ "NGN",
981
+ "GHS",
982
+ "ZAR",
983
+ "KES",
984
+ "UGX",
985
+ "TZS",
986
+ "XAF",
987
+ "XOF",
988
+ "USD"
989
+ ]
990
+ },
991
+ {
992
+ parameter: "customer",
993
+ required: false,
994
+ type: "String",
995
+ description: "Customer ID (only works in draft mode)"
996
+ }
997
+ ],
998
+ description: "Update a payment request"
999
+ },
1000
+ {
1001
+ api: "verify",
1002
+ endpoint: "https://api.paystack.co/paymentrequest/verify/{id}",
1003
+ method: "GET",
1004
+ params: [{
1005
+ parameter: "id",
1006
+ required: false,
1007
+ type: "String",
1008
+ description: "The invoice code for the Payment Request to be verified",
1009
+ paramType: "path"
1010
+ }],
1011
+ description: "Verify details of a payment request on your integration."
1012
+ }
1013
+ ],
1014
+ transferrecipient: [
1015
+ {
1016
+ api: "create",
1017
+ endpoint: "https://api.paystack.co/transferrecipient",
1018
+ method: "POST",
1019
+ params: [
1020
+ {
1021
+ parameter: "type",
1022
+ required: true,
1023
+ type: "String",
1024
+ description: "Recipient Type",
1025
+ options: [
1026
+ "nuban",
1027
+ "ghipss",
1028
+ "mobile_money",
1029
+ "basa"
1030
+ ]
1031
+ },
1032
+ {
1033
+ parameter: "name",
1034
+ required: true,
1035
+ type: "String",
1036
+ description: "A name for the recipient"
1037
+ },
1038
+ {
1039
+ parameter: "metadata",
1040
+ required: false,
1041
+ type: "String",
1042
+ description: "Additional information in structured JSON format"
1043
+ },
1044
+ {
1045
+ parameter: "bank_code",
1046
+ required: true,
1047
+ type: "String",
1048
+ description: "Bank code from the List Banks endpoint"
1049
+ },
1050
+ {
1051
+ parameter: "account_number",
1052
+ required: true,
1053
+ type: "String",
1054
+ description: "Bank account number (required if type is nuban)"
1055
+ },
1056
+ {
1057
+ parameter: "currency",
1058
+ required: false,
1059
+ type: "String",
1060
+ description: "Currency for the account receiving the transfer",
1061
+ options: [
1062
+ "NGN",
1063
+ "GHS",
1064
+ "ZAR",
1065
+ "KES",
1066
+ "UGX",
1067
+ "TZS",
1068
+ "XAF",
1069
+ "XOF",
1070
+ "USD"
1071
+ ]
1072
+ },
1073
+ {
1074
+ parameter: "description",
1075
+ required: false,
1076
+ type: "String",
1077
+ description: "Description for the recipient"
1078
+ }
1079
+ ],
1080
+ description: "Create a new transfer recipient"
1081
+ },
1082
+ {
1083
+ api: "delete",
1084
+ endpoint: "https://api.paystack.co/transferrecipient/{id_or_code}",
1085
+ method: "DELETE",
1086
+ params: [{
1087
+ parameter: "id_or_code",
1088
+ required: true,
1089
+ type: "String",
1090
+ description: "Transfer Recipient's ID or code",
1091
+ paramType: "path"
1092
+ }],
1093
+ description: "Delete a transfer recipient"
1094
+ },
1095
+ {
1096
+ api: "list",
1097
+ endpoint: "https://api.paystack.co/transferrecipient",
1098
+ method: "GET",
1099
+ params: [{
1100
+ parameter: "perPage",
1101
+ required: false,
1102
+ type: "String",
1103
+ description: "Specify how many records you want to retrieve per page"
1104
+ }, {
1105
+ parameter: "page",
1106
+ required: false,
1107
+ type: "Number",
1108
+ description: "Specify exactly what page you want to retrieve"
1109
+ }],
1110
+ description: "List all transfer recipients"
1111
+ },
1112
+ {
1113
+ api: "update",
1114
+ endpoint: "https://api.paystack.co/transferrecipient/{id_or_code}",
1115
+ method: "PUT",
1116
+ params: [{
1117
+ parameter: "id_or_code",
1118
+ required: true,
1119
+ type: "String",
1120
+ description: "Transfer Recipient's ID or code",
1121
+ paramType: "path"
1122
+ }],
1123
+ description: "Update a transfer recipient"
1124
+ }
1125
+ ],
1126
+ subscription: [
1127
+ {
1128
+ api: "disable",
1129
+ endpoint: "https://api.paystack.co/subscription/disable",
1130
+ method: "POST",
1131
+ params: [{
1132
+ parameter: "code",
1133
+ required: true,
1134
+ type: "String",
1135
+ description: "Subscription code"
1136
+ }, {
1137
+ parameter: "token",
1138
+ required: true,
1139
+ type: "String",
1140
+ description: "Email token"
1141
+ }],
1142
+ description: "Disable a subscription"
1143
+ },
1144
+ {
1145
+ api: "fetch",
1146
+ endpoint: ":id_or_subscription_code",
1147
+ method: "GET",
1148
+ params: [],
1149
+ description: "Fetch a specific subscription"
1150
+ },
1151
+ {
1152
+ api: "create",
1153
+ endpoint: "https://api.paystack.co/subscription",
1154
+ method: "POST",
1155
+ params: [
1156
+ {
1157
+ parameter: "customer",
1158
+ required: true,
1159
+ type: "String",
1160
+ description: "Customer email address or customer code"
1161
+ },
1162
+ {
1163
+ parameter: "plan",
1164
+ required: true,
1165
+ type: "String",
1166
+ description: "Plan code"
1167
+ },
1168
+ {
1169
+ parameter: "authorization",
1170
+ required: false,
1171
+ type: "String",
1172
+ description: "Authorization code (required if customer has multiple authorizations)"
1173
+ },
1174
+ {
1175
+ parameter: "start_date",
1176
+ required: false,
1177
+ type: "String",
1178
+ description: "Start date for the first debit (ISO 8601 format)"
1179
+ }
1180
+ ],
1181
+ description: "Create a subscription for a customer"
1182
+ },
1183
+ {
1184
+ api: "list",
1185
+ endpoint: "https://api.paystack.co/subscription",
1186
+ method: "GET",
1187
+ params: [
1188
+ {
1189
+ parameter: "perPage",
1190
+ required: false,
1191
+ type: "String",
1192
+ description: "Specify how many records you want to retrieve per page"
1193
+ },
1194
+ {
1195
+ parameter: "page",
1196
+ required: false,
1197
+ type: "Number",
1198
+ description: "Specify exactly what page you want to retrieve"
1199
+ },
1200
+ {
1201
+ parameter: "customer",
1202
+ required: false,
1203
+ type: "String",
1204
+ description: "Filter by Customer ID"
1205
+ },
1206
+ {
1207
+ parameter: "plan",
1208
+ required: false,
1209
+ type: "String",
1210
+ description: "Filter by Plan ID"
1211
+ }
1212
+ ],
1213
+ description: "List all subscriptions"
1214
+ },
1215
+ {
1216
+ api: "enable",
1217
+ endpoint: "https://api.paystack.co/subscription/enable",
1218
+ method: "POST",
1219
+ params: [{
1220
+ parameter: "code",
1221
+ required: true,
1222
+ type: "String",
1223
+ description: "Subscription code"
1224
+ }, {
1225
+ parameter: "token",
1226
+ required: true,
1227
+ type: "String",
1228
+ description: "Email token"
1229
+ }],
1230
+ description: "Enable a subscription"
1231
+ }
1232
+ ],
1233
+ bulkcharge: [
1234
+ {
1235
+ api: "fetch",
1236
+ endpoint: "https://api.paystack.co/bulkcharge/id_or_code",
1237
+ method: "GET",
1238
+ params: [{
1239
+ parameter: "id_or_code",
1240
+ required: true,
1241
+ type: "String",
1242
+ description: "An ID or code for the batch whose details you want to retrieve"
1243
+ }],
1244
+ description: "Fetch a specific bulk charge batch with progress information"
1245
+ },
1246
+ {
1247
+ api: "fetch",
1248
+ endpoint: "https://api.paystack.co/bulkcharge/id_or_code/charges",
1249
+ method: "GET",
1250
+ params: [
1251
+ {
1252
+ parameter: "id_or_code",
1253
+ required: true,
1254
+ type: "String",
1255
+ description: "An ID or code for the batch whose charges you want to retrieve"
1256
+ },
1257
+ {
1258
+ parameter: "status",
1259
+ required: false,
1260
+ type: "String",
1261
+ description: "Filter by status: \"pending\", \"success\", or \"failed\""
1262
+ },
1263
+ {
1264
+ parameter: "perPage",
1265
+ required: false,
1266
+ type: "String",
1267
+ description: "Specify how many records you want to retrieve per page"
1268
+ },
1269
+ {
1270
+ parameter: "page",
1271
+ required: false,
1272
+ type: "Number",
1273
+ description: "Specify exactly what page you want to retrieve"
1274
+ }
1275
+ ],
1276
+ description: "Retrieve all charges associated with a bulk charge batch"
1277
+ },
1278
+ {
1279
+ api: "initiate",
1280
+ endpoint: "https://api.paystack.co/bulkcharge",
1281
+ method: "POST",
1282
+ params: [],
1283
+ description: "Initiate a bulk charge by sending an array of authorization codes and amounts"
1284
+ },
1285
+ {
1286
+ api: "resume",
1287
+ endpoint: "https://api.paystack.co/bulkcharge/resume/batch_code",
1288
+ method: "GET",
1289
+ params: [{
1290
+ parameter: "batch_code",
1291
+ required: true,
1292
+ type: "String",
1293
+ description: "Code of the batch to resume processing"
1294
+ }],
1295
+ description: "Resume processing a paused bulk charge batch"
1296
+ },
1297
+ {
1298
+ api: "pause",
1299
+ endpoint: "https://api.paystack.co/bulkcharge/pause/batch_code",
1300
+ method: "GET",
1301
+ params: [{
1302
+ parameter: "batch_code",
1303
+ required: true,
1304
+ type: "String",
1305
+ description: "Code of the batch to pause"
1306
+ }],
1307
+ description: "Pause processing a bulk charge batch"
1308
+ }
1309
+ ],
1310
+ bank: [
1311
+ {
1312
+ api: "list",
1313
+ endpoint: "https://api.paystack.co/bank",
1314
+ method: "GET",
1315
+ params: [],
1316
+ description: "List all supported banks"
1317
+ },
1318
+ {
1319
+ api: "resolve",
1320
+ endpoint: "https://api.paystack.co/bank/resolve?account_number={account_number}&bank_code={bank_code}",
1321
+ method: "GET",
1322
+ params: [{
1323
+ parameter: "account_number",
1324
+ required: true,
1325
+ type: "String",
1326
+ description: "Bank account number",
1327
+ paramType: "path"
1328
+ }, {
1329
+ parameter: "bank_code",
1330
+ required: true,
1331
+ type: "String",
1332
+ description: "Bank code",
1333
+ paramType: "path"
1334
+ }],
1335
+ description: "Resolve account details by account number and bank code"
1336
+ },
1337
+ {
1338
+ api: "match",
1339
+ endpoint: "{account_number}&bank_code={bank_code}&bvn={bvn}",
1340
+ method: "GET",
1341
+ params: [
1342
+ {
1343
+ parameter: "account_number",
1344
+ required: true,
1345
+ type: "String",
1346
+ description: "Bank account number",
1347
+ paramType: "path"
1348
+ },
1349
+ {
1350
+ parameter: "bank_code",
1351
+ required: true,
1352
+ type: "String",
1353
+ description: "Bank code from List Bank endpoint",
1354
+ paramType: "path"
1355
+ },
1356
+ {
1357
+ parameter: "bvn",
1358
+ required: true,
1359
+ type: "String",
1360
+ description: "11 digit BVN",
1361
+ paramType: "path"
1362
+ }
1363
+ ],
1364
+ description: "Match account details with BVN for verification"
1365
+ }
1366
+ ],
1367
+ charge: [
1368
+ {
1369
+ api: "submit",
1370
+ endpoint: "https://api.paystack.co/charge/submit_otp",
1371
+ method: "POST",
1372
+ params: [{
1373
+ parameter: "otp",
1374
+ required: true,
1375
+ type: "String",
1376
+ description: "OTP submitted by user"
1377
+ }, {
1378
+ parameter: "reference",
1379
+ required: true,
1380
+ type: "String",
1381
+ description: "Reference for ongoing transaction"
1382
+ }],
1383
+ description: "Submit OTP to complete a charge"
1384
+ },
1385
+ {
1386
+ api: "submit",
1387
+ endpoint: "https://api.paystack.co/charge/submit_pin",
1388
+ method: "POST",
1389
+ params: [{
1390
+ parameter: "pin",
1391
+ required: true,
1392
+ type: "String",
1393
+ description: "PIN submitted by user"
1394
+ }, {
1395
+ parameter: "reference",
1396
+ required: true,
1397
+ type: "String",
1398
+ description: "Reference for transaction that requested PIN"
1399
+ }],
1400
+ description: "Submit PIN to complete a charge"
1401
+ },
1402
+ {
1403
+ api: "submit",
1404
+ endpoint: "https://api.paystack.co/charge/submit_birthday",
1405
+ method: "POST",
1406
+ params: [{
1407
+ parameter: "birthday",
1408
+ required: true,
1409
+ type: "String",
1410
+ description: "Birthday submitted by user"
1411
+ }, {
1412
+ parameter: "reference",
1413
+ required: true,
1414
+ type: "String",
1415
+ description: "Reference for ongoing transaction"
1416
+ }],
1417
+ description: "Submit birthday to complete a charge"
1418
+ },
1419
+ {
1420
+ api: "tokenize",
1421
+ endpoint: "https://api.paystack.co/charge/tokenize",
1422
+ method: "POST",
1423
+ params: [{
1424
+ parameter: "email",
1425
+ required: true,
1426
+ type: "String",
1427
+ description: "Customer email address"
1428
+ }, {
1429
+ parameter: "card",
1430
+ required: true,
1431
+ type: "String",
1432
+ description: "Card object containing number, cvv, expiry_month, and expiry_year"
1433
+ }],
1434
+ description: "Tokenize a card for future charges"
1435
+ },
1436
+ {
1437
+ api: "check",
1438
+ endpoint: "https://api.paystack.co/charge/reference",
1439
+ method: "GET",
1440
+ params: [{
1441
+ parameter: "reference",
1442
+ required: true,
1443
+ type: "String",
1444
+ description: "The reference to check"
1445
+ }],
1446
+ description: "Check the status of a charge transaction"
1447
+ },
1448
+ {
1449
+ api: "charge",
1450
+ endpoint: "https://api.paystack.co/charge",
1451
+ method: "POST",
1452
+ params: [
1453
+ {
1454
+ parameter: "email",
1455
+ required: true,
1456
+ type: "String",
1457
+ description: "Customer email address"
1458
+ },
1459
+ {
1460
+ parameter: "amount",
1461
+ required: true,
1462
+ type: "Number",
1463
+ description: "Amount in kobo"
1464
+ },
1465
+ {
1466
+ parameter: "card",
1467
+ required: false,
1468
+ type: "String",
1469
+ description: "Card object with number, cvv, expiry_month, and expiry_year"
1470
+ },
1471
+ {
1472
+ parameter: "bank",
1473
+ required: false,
1474
+ type: "String",
1475
+ description: "Bank object with code and account_number"
1476
+ },
1477
+ {
1478
+ parameter: "authorization_code",
1479
+ required: false,
1480
+ type: "String",
1481
+ description: "Valid authorization code to charge"
1482
+ },
1483
+ {
1484
+ parameter: "pin",
1485
+ required: false,
1486
+ type: "String",
1487
+ description: "4-digit PIN for non-reusable authorization code"
1488
+ },
1489
+ {
1490
+ parameter: "metadata",
1491
+ required: false,
1492
+ type: "String",
1493
+ description: "A JSON object for additional transaction data"
1494
+ }
1495
+ ],
1496
+ description: "Charge a customer using card, bank account, or authorization code"
1497
+ },
1498
+ {
1499
+ api: "submit",
1500
+ endpoint: "https://api.paystack.co/charge/submit_phone",
1501
+ method: "POST",
1502
+ params: [{
1503
+ parameter: "phone",
1504
+ required: true,
1505
+ type: "String",
1506
+ description: "Phone number submitted by user"
1507
+ }, {
1508
+ parameter: "reference",
1509
+ required: true,
1510
+ type: "String",
1511
+ description: "Reference for ongoing transaction"
1512
+ }],
1513
+ description: "Submit phone number to complete a charge"
1514
+ }
1515
+ ],
1516
+ transaction: [
1517
+ {
1518
+ api: "verify",
1519
+ endpoint: "https://api.paystack.co/transaction/verify/{reference}",
1520
+ method: "GET",
1521
+ params: [{
1522
+ parameter: "reference",
1523
+ required: true,
1524
+ type: "String",
1525
+ description: "Transaction reference to verify",
1526
+ paramType: "path"
1527
+ }],
1528
+ description: "Verify transaction status by reference"
1529
+ },
1530
+ {
1531
+ api: "list",
1532
+ endpoint: "https://api.paystack.co/transaction",
1533
+ method: "GET",
1534
+ params: [
1535
+ {
1536
+ parameter: "perPage",
1537
+ required: false,
1538
+ type: "String",
1539
+ description: "Specify how many records you want to retrieve per page"
1540
+ },
1541
+ {
1542
+ parameter: "page",
1543
+ required: false,
1544
+ type: "Number",
1545
+ description: "Specify exactly what page you want to retrieve"
1546
+ },
1547
+ {
1548
+ parameter: "customer",
1549
+ required: false,
1550
+ type: "String",
1551
+ description: "Specify an ID for the customer whose transactions you want to retrieve"
1552
+ },
1553
+ {
1554
+ parameter: "status",
1555
+ required: false,
1556
+ type: "String",
1557
+ description: "Filter transactions by status (\"failed\", \"success\", \"abandoned\")"
1558
+ },
1559
+ {
1560
+ parameter: "from",
1561
+ required: false,
1562
+ type: "String",
1563
+ description: "A timestamp from which to start listing transactions (e.g. 2016-09-24T00:00:05.000Z, 2016-09-21)"
1564
+ },
1565
+ {
1566
+ parameter: "to",
1567
+ required: false,
1568
+ type: "String",
1569
+ description: "A timestamp at which to stop listing transactions (e.g. 2016-09-24T00:00:05.000Z, 2016-09-21)"
1570
+ },
1571
+ {
1572
+ parameter: "amount",
1573
+ required: false,
1574
+ type: "Number",
1575
+ description: "Filter transactions by amount (in kobo)"
1576
+ }
1577
+ ],
1578
+ description: "List all transactions"
1579
+ },
1580
+ {
1581
+ api: "view",
1582
+ endpoint: ":id_or_reference",
1583
+ method: "GET",
1584
+ params: [],
1585
+ description: "View a specific transaction"
1586
+ },
1587
+ {
1588
+ api: "charge",
1589
+ endpoint: "https://api.paystack.co/transaction/charge_authorization",
1590
+ method: "POST",
1591
+ params: [
1592
+ {
1593
+ parameter: "authorization_code",
1594
+ required: true,
1595
+ type: "String",
1596
+ description: "Valid authorization code to charge"
1597
+ },
1598
+ {
1599
+ parameter: "email",
1600
+ required: true,
1601
+ type: "String",
1602
+ description: "Customer email address"
1603
+ },
1604
+ {
1605
+ parameter: "amount",
1606
+ required: true,
1607
+ type: "Number",
1608
+ description: "Amount in kobo"
1609
+ },
1610
+ {
1611
+ parameter: "reference",
1612
+ required: false,
1613
+ type: "String",
1614
+ description: "Unique transaction reference"
1615
+ },
1616
+ {
1617
+ parameter: "plan",
1618
+ required: false,
1619
+ type: "String",
1620
+ description: "Plan code for subscription"
1621
+ },
1622
+ {
1623
+ parameter: "currency",
1624
+ required: false,
1625
+ type: "String",
1626
+ description: "Currency to charge in",
1627
+ options: [
1628
+ "NGN",
1629
+ "GHS",
1630
+ "ZAR",
1631
+ "KES",
1632
+ "UGX",
1633
+ "TZS",
1634
+ "XAF",
1635
+ "XOF",
1636
+ "USD"
1637
+ ]
1638
+ },
1639
+ {
1640
+ parameter: "metadata",
1641
+ required: false,
1642
+ type: "String",
1643
+ description: "Additional transaction metadata"
1644
+ },
1645
+ {
1646
+ parameter: "subaccount",
1647
+ required: false,
1648
+ type: "String",
1649
+ description: "Subaccount code that owns the payment"
1650
+ },
1651
+ {
1652
+ parameter: "transaction_charge",
1653
+ required: false,
1654
+ type: "String",
1655
+ description: "Flat fee to charge the subaccount in kobo"
1656
+ },
1657
+ {
1658
+ parameter: "bearer",
1659
+ required: false,
1660
+ type: "String",
1661
+ description: "Who bears Paystack charges: \"account\" or \"subaccount\""
1662
+ },
1663
+ {
1664
+ parameter: "invoice_limit",
1665
+ required: false,
1666
+ type: "String",
1667
+ description: "Number of invoices to raise during subscription"
1668
+ }
1669
+ ],
1670
+ description: "Charge a customer using a stored authorization code"
1671
+ },
1672
+ {
1673
+ api: "export",
1674
+ endpoint: "https://api.paystack.co/transaction/export",
1675
+ method: "GET",
1676
+ params: [
1677
+ {
1678
+ arg: true,
1679
+ parameter: "from",
1680
+ required: false,
1681
+ type: "String",
1682
+ description: "Lower bound of date range"
1683
+ },
1684
+ {
1685
+ arg: true,
1686
+ parameter: "to",
1687
+ required: false,
1688
+ type: "String",
1689
+ description: "Upper bound of date range"
1690
+ },
1691
+ {
1692
+ parameter: "settled",
1693
+ required: false,
1694
+ type: "String",
1695
+ description: "Set to \"true\" for settled transactions or \"false\" for pending"
1696
+ },
1697
+ {
1698
+ parameter: "payment_page",
1699
+ required: false,
1700
+ type: "String",
1701
+ description: "Payment page ID to filter transactions"
1702
+ },
1703
+ {
1704
+ parameter: "customer",
1705
+ required: false,
1706
+ type: "String",
1707
+ description: "Customer ID to filter transactions"
1708
+ },
1709
+ {
1710
+ parameter: "currency",
1711
+ required: false,
1712
+ type: "String",
1713
+ description: "Currency to filter transactions",
1714
+ options: [
1715
+ "NGN",
1716
+ "GHS",
1717
+ "ZAR",
1718
+ "KES",
1719
+ "UGX",
1720
+ "TZS",
1721
+ "XAF",
1722
+ "XOF",
1723
+ "USD"
1724
+ ]
1725
+ },
1726
+ {
1727
+ parameter: "settlement",
1728
+ required: false,
1729
+ type: "String",
1730
+ description: "Settlement ID to filter transactions"
1731
+ },
1732
+ {
1733
+ parameter: "amount",
1734
+ required: false,
1735
+ type: "Number",
1736
+ description: "Amount to filter transactions"
1737
+ },
1738
+ {
1739
+ parameter: "status",
1740
+ required: false,
1741
+ type: "String",
1742
+ description: "Status to filter transactions"
1743
+ }
1744
+ ],
1745
+ description: "Export transactions to CSV"
1746
+ },
1747
+ {
1748
+ api: "check",
1749
+ endpoint: "https://api.paystack.co/transaction/check_authorization",
1750
+ method: "POST",
1751
+ params: [
1752
+ {
1753
+ parameter: "authorization_code",
1754
+ required: true,
1755
+ type: "String",
1756
+ description: "Authorization code for Mastercard or VISA"
1757
+ },
1758
+ {
1759
+ parameter: "amount",
1760
+ required: true,
1761
+ type: "Number",
1762
+ description: "Amount in kobo to check"
1763
+ },
1764
+ {
1765
+ parameter: "email",
1766
+ required: true,
1767
+ type: "String",
1768
+ description: "Customer email address"
1769
+ },
1770
+ {
1771
+ parameter: "currency",
1772
+ required: false,
1773
+ type: "String",
1774
+ description: "Currency for the amount to check",
1775
+ options: [
1776
+ "NGN",
1777
+ "GHS",
1778
+ "ZAR",
1779
+ "KES",
1780
+ "UGX",
1781
+ "TZS",
1782
+ "XAF",
1783
+ "XOF",
1784
+ "USD"
1785
+ ]
1786
+ }
1787
+ ],
1788
+ description: "Check if an authorization code has sufficient funds"
1789
+ },
1790
+ {
1791
+ api: "transaction",
1792
+ endpoint: "https://api.paystack.co/transaction/totals",
1793
+ method: "GET",
1794
+ params: [{
1795
+ arg: true,
1796
+ parameter: "from",
1797
+ required: false,
1798
+ type: "String",
1799
+ description: "Lower bound of date range"
1800
+ }, {
1801
+ arg: true,
1802
+ parameter: "to",
1803
+ required: false,
1804
+ type: "String",
1805
+ description: "Upper bound of date range"
1806
+ }],
1807
+ description: "Get total amount received on your account"
1808
+ },
1809
+ {
1810
+ api: "initialize",
1811
+ endpoint: "https://api.paystack.co/transaction/initialize",
1812
+ method: "POST",
1813
+ params: [
1814
+ {
1815
+ parameter: "email",
1816
+ required: true,
1817
+ type: "String",
1818
+ description: "Customer email address"
1819
+ },
1820
+ {
1821
+ parameter: "amount",
1822
+ required: true,
1823
+ type: "Number",
1824
+ description: "Amount in kobo"
1825
+ },
1826
+ {
1827
+ parameter: "reference",
1828
+ required: false,
1829
+ type: "String",
1830
+ description: "Unique transaction reference or leave blank for auto-generation"
1831
+ },
1832
+ {
1833
+ parameter: "callback_url",
1834
+ required: false,
1835
+ type: "String",
1836
+ description: "URL to redirect to after payment"
1837
+ },
1838
+ {
1839
+ parameter: "plan",
1840
+ required: false,
1841
+ type: "String",
1842
+ description: "Plan code for subscription"
1843
+ },
1844
+ {
1845
+ parameter: "invoice_limit",
1846
+ required: false,
1847
+ type: "String",
1848
+ description: "Number of invoices to raise during subscription"
1849
+ },
1850
+ {
1851
+ parameter: "metadata",
1852
+ required: false,
1853
+ type: "String",
1854
+ description: "Additional transaction metadata"
1855
+ },
1856
+ {
1857
+ parameter: "subaccount",
1858
+ required: false,
1859
+ type: "String",
1860
+ description: "Subaccount code that owns the payment"
1861
+ },
1862
+ {
1863
+ parameter: "transaction_charge",
1864
+ required: false,
1865
+ type: "String",
1866
+ description: "Flat fee to charge the subaccount in kobo"
1867
+ },
1868
+ {
1869
+ parameter: "bearer",
1870
+ required: false,
1871
+ type: "String",
1872
+ description: "Who bears Paystack charges (defaults to \"account\")"
1873
+ },
1874
+ {
1875
+ parameter: "channels",
1876
+ required: false,
1877
+ type: "String",
1878
+ description: "Payment channels to enable: \"card\", \"bank\", or both as array"
1879
+ }
1880
+ ],
1881
+ description: "Initialize a transaction"
1882
+ },
1883
+ {
1884
+ api: "fetch",
1885
+ endpoint: "https://api.paystack.co/transaction/id",
1886
+ method: "GET",
1887
+ params: [{
1888
+ parameter: "id",
1889
+ required: true,
1890
+ type: "String",
1891
+ description: "An ID for the transaction to fetch"
1892
+ }],
1893
+ description: "Fetch transaction details by ID"
1894
+ }
1895
+ ],
1896
+ plan: [
1897
+ {
1898
+ api: "update",
1899
+ endpoint: ":id_or_plan_code",
1900
+ method: "PUT",
1901
+ params: [
1902
+ {
1903
+ parameter: "name",
1904
+ required: false,
1905
+ type: "String",
1906
+ description: "Name of plan"
1907
+ },
1908
+ {
1909
+ parameter: "description",
1910
+ required: false,
1911
+ type: "String",
1912
+ description: "Short description of plan"
1913
+ },
1914
+ {
1915
+ parameter: "amount",
1916
+ required: false,
1917
+ type: "Number",
1918
+ description: "Amount to charge in kobo (will override amount for existing subscriptions)"
1919
+ },
1920
+ {
1921
+ parameter: "interval",
1922
+ required: false,
1923
+ type: "String",
1924
+ description: "Billing interval (hourly, daily, weekly, monthly, annually)"
1925
+ },
1926
+ {
1927
+ parameter: "send_invoices",
1928
+ required: false,
1929
+ type: "String",
1930
+ description: "Set to false to disable invoice emails"
1931
+ },
1932
+ {
1933
+ parameter: "send_sms",
1934
+ required: false,
1935
+ type: "String",
1936
+ description: "Set to false to disable SMS notifications"
1937
+ },
1938
+ {
1939
+ parameter: "currency",
1940
+ required: false,
1941
+ type: "String",
1942
+ description: "Currency for the amount",
1943
+ options: [
1944
+ "NGN",
1945
+ "GHS",
1946
+ "ZAR",
1947
+ "KES",
1948
+ "UGX",
1949
+ "TZS",
1950
+ "XAF",
1951
+ "XOF",
1952
+ "USD"
1953
+ ]
1954
+ },
1955
+ {
1956
+ parameter: "invoice_limit",
1957
+ required: false,
1958
+ type: "String",
1959
+ description: "Number of invoices to raise during subscription (will not override active subscriptions)"
1960
+ }
1961
+ ],
1962
+ description: "Update a plan"
1963
+ },
1964
+ {
1965
+ api: "create",
1966
+ endpoint: "https://api.paystack.co/plan",
1967
+ method: "POST",
1968
+ params: [
1969
+ {
1970
+ parameter: "name",
1971
+ required: true,
1972
+ type: "String",
1973
+ description: "Name of plan"
1974
+ },
1975
+ {
1976
+ parameter: "description",
1977
+ required: false,
1978
+ type: "String",
1979
+ description: "Short description of plan"
1980
+ },
1981
+ {
1982
+ parameter: "amount",
1983
+ required: true,
1984
+ type: "Number",
1985
+ description: "Amount to charge in kobo"
1986
+ },
1987
+ {
1988
+ parameter: "interval",
1989
+ required: true,
1990
+ type: "String",
1991
+ description: "Billing interval (hourly, daily, weekly, monthly, annually)"
1992
+ },
1993
+ {
1994
+ parameter: "send_invoices",
1995
+ required: false,
1996
+ type: "String",
1997
+ description: "Set to false to disable invoice emails"
1998
+ },
1999
+ {
2000
+ parameter: "currency",
2001
+ required: false,
2002
+ type: "String",
2003
+ description: "Currency for the amount",
2004
+ options: [
2005
+ "NGN",
2006
+ "GHS",
2007
+ "ZAR",
2008
+ "KES",
2009
+ "UGX",
2010
+ "TZS",
2011
+ "XAF",
2012
+ "XOF",
2013
+ "USD"
2014
+ ]
2015
+ },
2016
+ {
2017
+ parameter: "invoice_limit",
2018
+ required: false,
2019
+ type: "String",
2020
+ description: "Number of invoices to raise during subscription"
2021
+ }
2022
+ ],
2023
+ description: "Create a new plan"
2024
+ },
2025
+ {
2026
+ api: "list",
2027
+ endpoint: "https://api.paystack.co/plan",
2028
+ method: "GET",
2029
+ params: [
2030
+ {
2031
+ parameter: "perPage",
2032
+ required: false,
2033
+ type: "String",
2034
+ description: "Specify how many records you want to retrieve per page"
2035
+ },
2036
+ {
2037
+ parameter: "page",
2038
+ required: false,
2039
+ type: "Number",
2040
+ description: "Specify exactly what page you want to retrieve"
2041
+ },
2042
+ {
2043
+ parameter: "interval",
2044
+ required: false,
2045
+ type: "String",
2046
+ description: "Filter list by plans with specified interval"
2047
+ },
2048
+ {
2049
+ parameter: "amount",
2050
+ required: false,
2051
+ type: "Number",
2052
+ description: "Filter list by plans with specified amount (in kobo)"
2053
+ }
2054
+ ],
2055
+ description: "List all plans"
2056
+ },
2057
+ {
2058
+ api: "fetch",
2059
+ endpoint: "https://api.paystack.co/plan/id_or_plan_code",
2060
+ method: "GET",
2061
+ params: [],
2062
+ description: "Fetch a specific plan"
2063
+ }
2064
+ ],
2065
+ customer: [
2066
+ {
2067
+ api: "update",
2068
+ endpoint: "https://api.paystack.co/customer/:ID_OR_CUSTOMER_CODE",
2069
+ method: "PUT",
2070
+ params: [
2071
+ {
2072
+ parameter: "first_name",
2073
+ required: false,
2074
+ type: "String",
2075
+ description: "Customer first name"
2076
+ },
2077
+ {
2078
+ parameter: "last_name",
2079
+ required: false,
2080
+ type: "String",
2081
+ description: "Customer last name"
2082
+ },
2083
+ {
2084
+ parameter: "phone",
2085
+ required: false,
2086
+ type: "String",
2087
+ description: "Customer phone number"
2088
+ },
2089
+ {
2090
+ parameter: "metadata",
2091
+ required: false,
2092
+ type: "String",
2093
+ description: "Additional customer information in structured JSON format"
2094
+ }
2095
+ ],
2096
+ description: "Update customer details"
2097
+ },
2098
+ {
2099
+ api: "list",
2100
+ endpoint: "https://api.paystack.co/customer",
2101
+ method: "GET",
2102
+ params: [{
2103
+ parameter: "perPage",
2104
+ required: false,
2105
+ type: "String",
2106
+ description: "Specify how many records you want to retrieve per page"
2107
+ }, {
2108
+ parameter: "page",
2109
+ required: false,
2110
+ type: "Number",
2111
+ description: "Specify exactly what page you want to retrieve"
2112
+ }],
2113
+ description: "List all customers"
2114
+ },
2115
+ {
2116
+ api: "create",
2117
+ endpoint: "https://api.paystack.co/customer",
2118
+ method: "POST",
2119
+ params: [
2120
+ {
2121
+ parameter: "email",
2122
+ required: true,
2123
+ type: "String",
2124
+ description: "Customer email address"
2125
+ },
2126
+ {
2127
+ parameter: "first_name",
2128
+ required: false,
2129
+ type: "String",
2130
+ description: "Customer first name"
2131
+ },
2132
+ {
2133
+ parameter: "last_name",
2134
+ required: false,
2135
+ type: "String",
2136
+ description: "Customer last name"
2137
+ },
2138
+ {
2139
+ parameter: "phone",
2140
+ required: false,
2141
+ type: "String",
2142
+ description: "Customer phone number"
2143
+ },
2144
+ {
2145
+ parameter: "metadata",
2146
+ required: false,
2147
+ type: "String",
2148
+ description: "Additional customer information in structured JSON format"
2149
+ }
2150
+ ],
2151
+ description: "Create a new customer"
2152
+ },
2153
+ {
2154
+ api: "fetch",
2155
+ endpoint: ":id_or_customer_code",
2156
+ method: "GET",
2157
+ params: [{
2158
+ parameter: "exclude_transactions",
2159
+ required: false,
2160
+ type: "String",
2161
+ description: "By default, fetching a customer returns all their transactions. Set this to true to disable this behaviour"
2162
+ }],
2163
+ description: "Fetch a specific customer"
2164
+ },
2165
+ {
2166
+ api: "set_risk_action",
2167
+ endpoint: "https://api.paystack.co/customer/set_risk_action",
2168
+ method: "POST",
2169
+ params: [{
2170
+ parameter: "customer",
2171
+ required: false,
2172
+ type: "String",
2173
+ description: "Customer ID, code, or email address"
2174
+ }, {
2175
+ parameter: "risk_action",
2176
+ required: false,
2177
+ type: "String",
2178
+ description: "One of the possible risk actions. \"allow\" to whitelist, \"deny\" to blacklist"
2179
+ }],
2180
+ description: "Set customer risk action (whitelist or blacklist)"
2181
+ },
2182
+ {
2183
+ api: "deactivate",
2184
+ endpoint: "https://api.paystack.co/customer/deactivate_authorization",
2185
+ method: "POST",
2186
+ params: [{
2187
+ parameter: "authorization_code",
2188
+ required: true,
2189
+ type: "String",
2190
+ description: "Authorization code to deactivate"
2191
+ }],
2192
+ description: "Deactivate an authorization for a customer"
2193
+ }
2194
+ ],
2195
+ refund: [
2196
+ {
2197
+ api: "create",
2198
+ endpoint: "https://api.paystack.co/refund",
2199
+ method: "POST",
2200
+ params: [
2201
+ {
2202
+ parameter: "transaction",
2203
+ required: true,
2204
+ type: "String",
2205
+ description: "Transaction reference or ID to refund"
2206
+ },
2207
+ {
2208
+ parameter: "amount",
2209
+ required: false,
2210
+ type: "Number",
2211
+ description: "Amount to refund in kobo (defaults to full transaction amount)"
2212
+ },
2213
+ {
2214
+ parameter: "currency",
2215
+ required: false,
2216
+ type: "String",
2217
+ description: "Three-letter ISO currency code",
2218
+ options: [
2219
+ "NGN",
2220
+ "GHS",
2221
+ "ZAR",
2222
+ "KES",
2223
+ "UGX",
2224
+ "TZS",
2225
+ "XAF",
2226
+ "XOF",
2227
+ "USD"
2228
+ ]
2229
+ },
2230
+ {
2231
+ parameter: "customer_note",
2232
+ required: false,
2233
+ type: "String",
2234
+ description: "Customer-facing reason for refund"
2235
+ },
2236
+ {
2237
+ parameter: "merchant_note",
2238
+ required: false,
2239
+ type: "String",
2240
+ description: "Internal merchant reason for refund"
2241
+ }
2242
+ ],
2243
+ description: "Create a refund for a transaction"
2244
+ },
2245
+ {
2246
+ api: "fetch",
2247
+ endpoint: ":id",
2248
+ method: "GET",
2249
+ params: [{
2250
+ parameter: "id",
2251
+ required: false,
2252
+ type: "String",
2253
+ description: "ID of the refund to retrieve"
2254
+ }],
2255
+ description: "Fetch refund details by ID"
2256
+ },
2257
+ {
2258
+ api: "list",
2259
+ endpoint: "https://api.paystack.co/refund",
2260
+ method: "GET",
2261
+ params: [{
2262
+ parameter: "transaction",
2263
+ required: false,
2264
+ type: "String",
2265
+ description: "Filter by transaction"
2266
+ }, {
2267
+ parameter: "currency",
2268
+ required: false,
2269
+ type: "String",
2270
+ description: "Filter by currency",
2271
+ options: [
2272
+ "NGN",
2273
+ "GHS",
2274
+ "ZAR",
2275
+ "KES",
2276
+ "UGX",
2277
+ "TZS",
2278
+ "XAF",
2279
+ "XOF",
2280
+ "USD"
2281
+ ]
2282
+ }],
2283
+ description: "List all refunds"
2284
+ }
2285
+ ],
2286
+ integration: [{
2287
+ api: "update",
2288
+ endpoint: "https://api.paystack.co/integration/payment_session_timeout",
2289
+ method: "PUT",
2290
+ params: [{
2291
+ parameter: "timeout",
2292
+ required: false,
2293
+ type: "String",
2294
+ description: "Session timeout in seconds (set to 0 to disable session timeouts)"
2295
+ }],
2296
+ description: "Update payment session timeout setting"
2297
+ }, {
2298
+ api: "fetch",
2299
+ endpoint: "https://api.paystack.co/integration/payment_session_timeout",
2300
+ method: "GET",
2301
+ params: [],
2302
+ description: "Fetch payment session timeout setting"
2303
+ }],
2304
+ balance: [{
2305
+ api: "check",
2306
+ endpoint: "https://api.paystack.co/balance",
2307
+ method: "GET",
2308
+ params: [],
2309
+ description: "You can only transfer from what you have"
2310
+ }, {
2311
+ api: "balance",
2312
+ endpoint: "https://api.paystack.co/balance/ledger",
2313
+ method: "GET",
2314
+ params: [],
2315
+ description: "Retrieve account balance ledger activity"
2316
+ }],
2317
+ settlement: [{
2318
+ api: "fetch",
2319
+ endpoint: "https://api.paystack.co/settlement",
2320
+ method: "GET",
2321
+ params: [
2322
+ {
2323
+ arg: true,
2324
+ parameter: "from",
2325
+ required: false,
2326
+ type: "String",
2327
+ description: "Lower bound of date range. Leave undefined to export settlement from day one"
2328
+ },
2329
+ {
2330
+ arg: true,
2331
+ parameter: "to",
2332
+ required: false,
2333
+ type: "String",
2334
+ description: "Upper bound of date range. Leave undefined to export settlements till date"
2335
+ },
2336
+ {
2337
+ parameter: "subaccount",
2338
+ required: false,
2339
+ type: "String",
2340
+ description: "Provide a subaccount code to export only settlements for that subaccount. Set to \"none\" to export only transactions for the account"
2341
+ }
2342
+ ],
2343
+ description: "Retrieve settlements made to your bank accounts"
2344
+ }],
2345
+ decision: [{
2346
+ api: "resolve",
2347
+ endpoint: "{BIN)",
2348
+ method: "GET",
2349
+ params: [{
2350
+ parameter: "bin",
2351
+ required: true,
2352
+ type: "String",
2353
+ description: "First 6 characters of card"
2354
+ }],
2355
+ description: "Resolve card information by BIN"
2356
+ }],
2357
+ invoice: [{
2358
+ api: "archive",
2359
+ endpoint: ":id_or_code",
2360
+ method: "POST",
2361
+ params: [],
2362
+ description: "Archive an invoice to prevent it from being fetched or verified"
2363
+ }],
2364
+ verifications: [{
2365
+ api: "resolve",
2366
+ endpoint: "https://api.paystack.co/verifications",
2367
+ method: "POST",
2368
+ params: [
2369
+ {
2370
+ parameter: "verification_type",
2371
+ required: true,
2372
+ type: "String",
2373
+ description: "Type of verification to perform"
2374
+ },
2375
+ {
2376
+ parameter: "phone",
2377
+ required: true,
2378
+ type: "String",
2379
+ description: "Customer phone number with country code (no + prefix)"
2380
+ },
2381
+ {
2382
+ parameter: "callback_url",
2383
+ required: false,
2384
+ type: "String",
2385
+ description: "URL to receive verification details"
2386
+ }
2387
+ ],
2388
+ description: "Verify customer authenticity using Truecaller API"
2389
+ }]
2390
+ };
2391
+ var apis_default = APIs;
2392
+
2393
+ //#endregion
2394
+ //#region src/utils/argument.ts
2395
+ /**
2396
+ * We would build a command signature string from an array of arguments.
2397
+ * Musket command signature for arguments follow this format:
2398
+ *
2399
+ * - Optional arguments: {argumentName?}
2400
+ * - Required arguments: {argumentName}
2401
+ * - Optional argument with a default value: {argumentName=defaultValue}
2402
+ * - Arguments with description: {argumentName : description}
2403
+ * - Arguments Expecting multiple values: {argumentName*}
2404
+ *
2405
+ * - Boolean flags are represented as: {--flag-name}
2406
+ * - Flags expecting values are represented as: {--flag-name=}
2407
+ * - Flags with description: {--flag-name : description}
2408
+ * - Flags expecting multiple values: {--flag-name=*}
2409
+ * - Flags with choices: {--flag-name : : choice1,choice2,choice3}
2410
+ * - Or {--flag-name : description : choice1,choice2,choice3}
2411
+ *
2412
+ * For shortcuts: {--F|flag-name}
2413
+ * We will extract the first letter before the pipe as the shortcut, but we also
2414
+ * need to ensure it is not already used by another option, in which case we check
2415
+ * if the string is a multiword (camel, dash, underscore separated) then we try to use the first letter of the second word.
2416
+ *
2417
+ * XParam properties used:
2418
+ * - parameter: The name of the argument or flag.
2419
+ * - required: A boolean indicating if the argument is required.
2420
+ * - type: The type of the argument (String, Number, Boolean, Array, Object).
2421
+ * - description: An optional description for the argument.
2422
+ * - default: An optional default value for the argument.
2423
+ * - options: An optional array of choices for the argument.
2424
+ *
2425
+ * We will make required arguments with defaults arguments.
2426
+ * Everything else would be flags.
2427
+ *
2428
+ *
2429
+ * @param args
2430
+ */
2431
+ const buildSignature = (param, cmd) => {
2432
+ const [_, setShortcut] = useShortcuts();
2433
+ let signature = "";
2434
+ if ((!param.required || param.default !== void 0 || param.type === "Boolean" || param.options) && param.paramType !== "path" && param.arg !== true) {
2435
+ signature += "{--";
2436
+ if (setShortcut(cmd + ":" + param.parameter.charAt(0).toLowerCase())) signature += `${param.parameter.charAt(0).toLowerCase()}|`;
2437
+ else {
2438
+ const words = param.parameter.split(/[_-\s]/);
2439
+ if (words.length > 1) {
2440
+ if (setShortcut(cmd + ":" + words[1].charAt(0).toLowerCase())) signature += `${words[1].charAt(0).toLowerCase()}|`;
2441
+ }
2442
+ }
2443
+ signature += `${param.parameter}`;
2444
+ if (param.type !== "Boolean") signature += param.default ? `=${param.default}` : "?";
2445
+ if (param.description) signature += ` : ${param.description}`;
2446
+ if (param.options) {
2447
+ const optionsStr = param.options.join(",");
2448
+ signature += ` : ${optionsStr}`;
2449
+ }
2450
+ signature += "}";
2451
+ } else {
2452
+ signature += `{${param.parameter}`;
2453
+ if (param.default) signature += `=${param.default}`;
2454
+ if (param.description) signature += ` : ${param.description}`;
2455
+ signature += "}";
2456
+ }
2457
+ return signature;
2458
+ };
2459
+
2460
+ //#endregion
2461
+ //#region src/utils/renderer.ts
2462
+ /**
2463
+ * We will recursively map through the result data and log each key value pair
2464
+ * as we apply coloring based on the value type.
2465
+ * We also need to handle root or nested objects and arrays while considering
2466
+ * indentation for better readability.
2467
+ *
2468
+ * @param data
2469
+ */
2470
+ const dataRenderer = (data) => {
2471
+ const render = (obj, indent = 0) => {
2472
+ const indentation = " ".repeat(indent);
2473
+ for (const key in obj) {
2474
+ const value = obj[key];
2475
+ if (typeof value === "object" && value !== null) {
2476
+ console.log(`${indentation}${stringFormatter(key)}:`);
2477
+ render(value, indent + 2);
2478
+ } else {
2479
+ let coloredValue;
2480
+ switch (typeof value) {
2481
+ case "string":
2482
+ coloredValue = __h3ravel_shared.Logger.log(value, "green", false);
2483
+ break;
2484
+ case "number":
2485
+ coloredValue = __h3ravel_shared.Logger.log(String(value), "yellow", false);
2486
+ break;
2487
+ case "boolean":
2488
+ coloredValue = __h3ravel_shared.Logger.log(String(value), "blue", false);
2489
+ break;
2490
+ default: coloredValue = value;
2491
+ }
2492
+ console.log(`${indentation}${stringFormatter(key)}: ${coloredValue}`);
2493
+ }
2494
+ }
2495
+ };
2496
+ render(data);
2497
+ };
2498
+ /**
2499
+ * We will format a string by replacing underscores and hyphens with spaces,
2500
+ * capitalizing the first letter of every word,
2501
+ * converting camelCase to spaced words,
2502
+ * and trimming any leading or trailing spaces.
2503
+ * If a sentence is only two letters long we will make it uppercase.
2504
+ *
2505
+ * @param str
2506
+ * @returns
2507
+ */
2508
+ const stringFormatter = (str) => {
2509
+ return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ").trim().replace(/^(\w{2})$/, (_, p1) => p1.toUpperCase());
2510
+ };
2511
+
2512
+ //#endregion
2513
+ //#region src/Commands/Commands.ts
2514
+ var Commands_default = () => {
2515
+ const commands = [];
2516
+ /**
2517
+ * We should map through the APIs and reduce all apis to a single key value pair
2518
+ * where key is the API key and the schema array entry api propety separated by a
2519
+ * semicolon and the value is schema array entry.
2520
+ */
2521
+ const entries = Object.entries(apis_default).reduce((acc, [key, schemas]) => {
2522
+ schemas.forEach((schema) => {
2523
+ const commandKey = key === schema.api ? key : `${key}:${schema.api}`;
2524
+ acc[commandKey] = schema;
2525
+ });
2526
+ return acc;
2527
+ }, {});
2528
+ for (const [key, schema] of Object.entries(entries)) {
2529
+ const args = schema.params.map((param) => buildSignature(param, key)).join("\n");
2530
+ const command = class extends __h3ravel_musket.Command {
2531
+ signature = `${key} \n${args}`;
2532
+ description = schema.description || "No description available.";
2533
+ handle = async () => {
2534
+ const [_, setCommand] = useCommand();
2535
+ setCommand(this);
2536
+ for (const param of schema.params) if (param.required && !this.argument(param.parameter)) return void this.newLine().error(`Missing required argument: ${param.parameter}`).newLine();
2537
+ const selected_integration = read("selected_integration")?.id;
2538
+ const user = read("user")?.id;
2539
+ if (!selected_integration || !user) {
2540
+ this.error("ERROR: You're not signed in, please run the [login] command before you begin").newLine();
2541
+ return;
2542
+ }
2543
+ this.newLine();
2544
+ const spinner = (0, ora.default)("Loading...\n").start();
2545
+ const [err, result] = await promiseWrapper(executeSchema(schema, {
2546
+ ...this.options(),
2547
+ ...this.arguments()
2548
+ }));
2549
+ if (err || !result) return void spinner.fail((err || "An error occurred") + "\n");
2550
+ spinner.succeed(result.message);
2551
+ this.newLine();
2552
+ dataRenderer(result.data);
2553
+ this.newLine();
2554
+ };
2555
+ };
2556
+ commands.push(command);
2557
+ }
2558
+ return commands;
2559
+ };
2560
+
2561
+ //#endregion
2562
+ //#region src/utils/config.ts
2563
+ const configChoices = (config) => {
2564
+ return [
2565
+ {
2566
+ name: "Debug Mode",
2567
+ value: "debug",
2568
+ description: `Enable or disable debug mode (${config.debug ? "Enabled" : "Disabled"})`
2569
+ },
2570
+ {
2571
+ name: "API Base URL",
2572
+ value: "apiBaseURL",
2573
+ description: `Set the base URL for the API (${config.apiBaseURL})`
2574
+ },
2575
+ {
2576
+ name: "Timeout Duration",
2577
+ value: "timeoutDuration",
2578
+ description: `Set the timeout duration for API requests (${config.timeoutDuration} ms)`
2579
+ },
2580
+ {
2581
+ name: "Ngrok Auth Token",
2582
+ value: "ngrokAuthToken",
2583
+ description: `Set the Ngrok Auth Token - will default to environment variable if not set (${config.ngrokAuthToken ? "************" : "Not Set"})`
2584
+ },
2585
+ {
2586
+ name: "Reset Configuration",
2587
+ value: "reset",
2588
+ description: "Reset all configurations to default values"
2589
+ }
2590
+ ];
2591
+ };
2592
+ const saveConfig = async (choice) => {
2593
+ const [getConfig, setConfig] = useConfig();
2594
+ const [command] = useCommand();
2595
+ let config = getConfig();
2596
+ if (choice === "debug") {
2597
+ const debug = await command().confirm(`${config.debug ? "Dis" : "En"}able debug mode?`, config.debug === true);
2598
+ config.debug = config.debug !== debug;
2599
+ } else if (choice === "apiBaseURL") config.apiBaseURL = await command().ask("Enter API Base URL", config.apiBaseURL);
2600
+ else if (choice === "ngrokAuthToken") config.ngrokAuthToken = await command().ask("Enter Ngrok Auth Token", config.ngrokAuthToken || "");
2601
+ else if (choice === "timeoutDuration") {
2602
+ const timeoutDuration = await command().ask("Enter Timeout Duration (in ms)", config.timeoutDuration.toString());
2603
+ config.timeoutDuration = parseInt(timeoutDuration);
2604
+ } else if (choice === "reset") config = {
2605
+ debug: false,
2606
+ apiBaseURL: "https://api.paystack.co",
2607
+ timeoutDuration: 3e3
2608
+ };
2609
+ setConfig(config);
2610
+ };
2611
+
2612
+ //#endregion
2613
+ //#region src/Commands/ConfigCommand.ts
2614
+ var ConfigCommand = class extends __h3ravel_musket.Command {
2615
+ signature = "config";
2616
+ description = "Configure paystack cli";
2617
+ async handle() {
2618
+ const [_, setCommand] = useCommand();
2619
+ setCommand(this);
2620
+ const [getConfig, setConfig] = useConfig();
2621
+ let config = getConfig();
2622
+ if (!config) {
2623
+ config = {
2624
+ debug: false,
2625
+ apiBaseURL: "https://api.paystack.co",
2626
+ timeoutDuration: 3e3
2627
+ };
2628
+ setConfig(config);
2629
+ }
2630
+ await saveConfig(await this.choice("Select configuration to set", configChoices(config)));
2631
+ this.info("Configuration updated successfully!").newLine();
2632
+ }
2633
+ };
2634
+
2635
+ //#endregion
2636
+ //#region src/Commands/InitCommand.ts
2637
+ var InitCommand = class extends __h3ravel_musket.Command {
2638
+ signature = "init";
2639
+ description = "Initialize the application.";
2640
+ async handle() {
2641
+ const [_, setCommand] = useCommand();
2642
+ setCommand(this);
2643
+ init();
2644
+ this.info("Application initialized successfully.").newLine();
2645
+ }
2646
+ };
2647
+
2648
+ //#endregion
2649
+ //#region src/paystack/webhooks.ts
2650
+ const webhook = {
2651
+ "charge.success": {
2652
+ event: "charge.success",
2653
+ data: {
2654
+ id: 302961,
2655
+ domain: "live",
2656
+ status: "success",
2657
+ reference: "qTPrJoy9Bx",
2658
+ amount: 1e4,
2659
+ message: null,
2660
+ gateway_response: "Approved by Financial Institution",
2661
+ paid_at: "2016-09-30T21:10:19.000Z",
2662
+ created_at: "2016-09-30T21:09:56.000Z",
2663
+ channel: "card",
2664
+ currency: "NGN",
2665
+ ip_address: "41.242.49.37",
2666
+ metadata: 0,
2667
+ log: {
2668
+ time_spent: 16,
2669
+ attempts: 1,
2670
+ authentication: "pin",
2671
+ errors: 0,
2672
+ success: false,
2673
+ mobile: false,
2674
+ input: [],
2675
+ channel: null,
2676
+ history: [
2677
+ {
2678
+ type: "input",
2679
+ message: "Filled these fields: card number, card expiry, card cvv",
2680
+ time: 15
2681
+ },
2682
+ {
2683
+ type: "action",
2684
+ message: "Attempted to pay",
2685
+ time: 15
2686
+ },
2687
+ {
2688
+ type: "auth",
2689
+ message: "Authentication Required: pin",
2690
+ time: 16
2691
+ }
2692
+ ]
2693
+ },
2694
+ fees: null,
2695
+ customer: {
2696
+ id: 68324,
2697
+ first_name: "BoJack",
2698
+ last_name: "Horseman",
2699
+ email: "bojack@horseman.com",
2700
+ customer_code: "CUS_qo38as2hpsgk2r0",
2701
+ phone: null,
2702
+ metadata: null,
2703
+ risk_action: "default"
2704
+ },
2705
+ authorization: {
2706
+ authorization_code: "AUTH_f5rnfq9p",
2707
+ bin: "539999",
2708
+ last4: "8877",
2709
+ exp_month: "08",
2710
+ exp_year: "2020",
2711
+ card_type: "mastercard DEBIT",
2712
+ bank: "Guaranty Trust Bank",
2713
+ country_code: "NG",
2714
+ brand: "mastercard"
2715
+ },
2716
+ plan: {}
2717
+ }
2718
+ },
2719
+ "transfer.success": {
2720
+ event: "transfer.success",
2721
+ data: {
2722
+ domain: "live",
2723
+ amount: 1e4,
2724
+ currency: "NGN",
2725
+ source: "balance",
2726
+ source_details: null,
2727
+ reason: "Bless you",
2728
+ recipient: {
2729
+ domain: "live",
2730
+ type: "nuban",
2731
+ currency: "NGN",
2732
+ name: "Someone",
2733
+ details: {
2734
+ account_number: "0123456789",
2735
+ account_name: null,
2736
+ bank_code: "058",
2737
+ bank_name: "Guaranty Trust Bank"
2738
+ },
2739
+ description: null,
2740
+ metadata: null,
2741
+ recipient_code: "RCP_xoosxcjojnvronx",
2742
+ active: true
2743
+ },
2744
+ status: "success",
2745
+ transfer_code: "TRF_zy6w214r4aw9971",
2746
+ transferred_at: "2017-03-25T17:51:24.000Z",
2747
+ created_at: "2017-03-25T17:48:54.000Z"
2748
+ }
2749
+ },
2750
+ "subscription.create": {
2751
+ event: "subscription.create",
2752
+ data: {
2753
+ domain: "test",
2754
+ status: "active",
2755
+ subscription_code: "SUB_vsyqdmlzble3uii",
2756
+ amount: 5e4,
2757
+ cron_expression: "0 0 28 * *",
2758
+ next_payment_date: "2016-05-19T07:00:00.000Z",
2759
+ open_invoice: null,
2760
+ createdAt: "2016-03-20T00:23:24.000Z",
2761
+ plan: {
2762
+ name: "Monthly retainer",
2763
+ plan_code: "PLN_gx2wn530m0i3w3m",
2764
+ description: null,
2765
+ amount: 5e4,
2766
+ interval: "monthly",
2767
+ send_invoices: true,
2768
+ send_sms: true,
2769
+ currency: "NGN"
2770
+ },
2771
+ authorization: {
2772
+ authorization_code: "AUTH_96xphygz",
2773
+ bin: "539983",
2774
+ last4: "7357",
2775
+ exp_month: "10",
2776
+ exp_year: "2017",
2777
+ card_type: "MASTERCARD DEBIT",
2778
+ bank: "GTBANK",
2779
+ country_code: "NG",
2780
+ brand: "MASTERCARD"
2781
+ },
2782
+ customer: {
2783
+ first_name: "BoJack",
2784
+ last_name: "Horseman",
2785
+ email: "bojack@horsinaround.com",
2786
+ customer_code: "CUS_xnxdt6s1zg1f4nx",
2787
+ phone: "",
2788
+ metadata: {},
2789
+ risk_action: "default"
2790
+ },
2791
+ created_at: "2016-10-01T10:59:59.000Z"
2792
+ }
2793
+ },
2794
+ "transfer.failed": {
2795
+ event: "transfer.failed",
2796
+ data: {
2797
+ domain: "test",
2798
+ amount: 1e4,
2799
+ currency: "NGN",
2800
+ source: "balance",
2801
+ source_details: null,
2802
+ reason: "Test",
2803
+ recipient: {
2804
+ domain: "live",
2805
+ type: "nuban",
2806
+ currency: "NGN",
2807
+ name: "Test account",
2808
+ details: {
2809
+ account_number: "0000000000",
2810
+ account_name: null,
2811
+ bank_code: "058",
2812
+ bank_name: "Zenith Bank"
2813
+ },
2814
+ description: null,
2815
+ metadata: null,
2816
+ recipient_code: "RCP_7um8q67gj0v4n1c",
2817
+ active: true
2818
+ },
2819
+ status: "failed",
2820
+ transfer_code: "TRF_3g8pc1cfmn00x6u",
2821
+ transferred_at: null,
2822
+ created_at: "2017-12-01T08:51:37.000Z"
2823
+ }
2824
+ }
2825
+ };
2826
+ var webhooks_default = webhook;
2827
+
2828
+ //#endregion
2829
+ //#region src/Paystack.ts
2830
+ /**
2831
+ * Select an integration
2832
+ *
2833
+ * @param integrations
2834
+ * @param token
2835
+ * @returns
2836
+ */
2837
+ async function selectIntegration(integrations, token) {
2838
+ const [command] = useCommand();
2839
+ const id = await command().choice("Choose an integration", integrations.map((e) => {
2840
+ return {
2841
+ value: e.id?.toString() || "",
2842
+ name: e.business_name || ""
2843
+ };
2844
+ }));
2845
+ return new Promise((resolve, reject) => {
2846
+ const integration = integrations.find((i) => i.id?.toString() === id);
2847
+ if (!integration) {
2848
+ reject("Invalid integration selected");
2849
+ return;
2850
+ }
2851
+ axios_default.post("/user/switch_integration", { integration: integration.id }, { headers: {
2852
+ Authorization: "Bearer " + token,
2853
+ "jwt-auth": true
2854
+ } }).then(() => {
2855
+ resolve(integration);
2856
+ }).catch((err) => {
2857
+ command().error("ERROR: " + err.response.data);
2858
+ reject(err);
2859
+ });
2860
+ });
2861
+ }
2862
+ /**
2863
+ * Refresh integration data
2864
+ *
2865
+ * @returns
2866
+ */
2867
+ async function refreshIntegration() {
2868
+ const [command] = useCommand();
2869
+ let token = "";
2870
+ const user_role = read("selected_integration").logged_in_user_role;
2871
+ const integration = read("selected_integration");
2872
+ if (parseInt(read("token_expiry")) * 1e3 > parseFloat(Date.now().toString())) {
2873
+ token = read("token");
2874
+ return true;
2875
+ } else {
2876
+ const password = await command().secret("What's your password: (" + read("user").email + ") \n>");
2877
+ const [err$1, result] = await promiseWrapper(signIn(read("user").email, password));
2878
+ if (err$1 || !result) return false;
2879
+ token = result.data.token;
2880
+ }
2881
+ const [err, integrationData] = await promiseWrapper(getIntegration(integration.id, token));
2882
+ if (err) {
2883
+ command().error("ERROR: " + err);
2884
+ return false;
2885
+ }
2886
+ if (integrationData) integrationData.logged_in_user_role = user_role;
2887
+ write("selected_integration", integrationData);
2888
+ }
2889
+ /**
2890
+ * Set webhook URL for an integration
2891
+ *
2892
+ * @param url
2893
+ * @param token
2894
+ * @param integrationId
2895
+ * @param domain
2896
+ * @returns
2897
+ */
2898
+ function setWebhook(url, token, integrationId, domain = "test") {
2899
+ return new Promise((resolve, reject) => {
2900
+ const data = {
2901
+ [domain + "_webhook_endpoint"]: url,
2902
+ integration: integrationId
2903
+ };
2904
+ axios_default.put("/integration/webhooks", data, { headers: {
2905
+ Authorization: "Bearer " + token,
2906
+ "jwt-auth": true
2907
+ } }).then((resp) => {
2908
+ const integration = read("selected_integration");
2909
+ write("selected_integration", {
2910
+ ...integration,
2911
+ [domain + "_webhook_endpoint"]: url
2912
+ });
2913
+ resolve(resp.data.message);
2914
+ }).catch((err) => {
2915
+ reject(err);
2916
+ });
2917
+ });
2918
+ }
2919
+ /**
2920
+ * Get integration keys
2921
+ *
2922
+ * @param token
2923
+ * @param type
2924
+ * @param domain
2925
+ * @returns
2926
+ */
2927
+ function getKeys(token, type = "secret", domain = "test") {
2928
+ return new Promise((resolve, reject) => {
2929
+ axios_default.get("/integration/keys", { headers: {
2930
+ Authorization: "Bearer " + token,
2931
+ "jwt-auth": true
2932
+ } }).then((response) => {
2933
+ let key = {};
2934
+ const keys = response.data.data;
2935
+ if (keys.length) {
2936
+ for (let i = 0; i < keys.length; i++) if (keys[i].domain === domain && keys[i].type === type) {
2937
+ key = keys[i];
2938
+ break;
2939
+ }
2940
+ }
2941
+ resolve(key.key);
2942
+ }).catch((error) => {
2943
+ if (error.response) {
2944
+ reject(error.response.data.message);
2945
+ return;
2946
+ }
2947
+ reject(error);
2948
+ });
2949
+ });
2950
+ }
2951
+ /**
2952
+ * Ping webhook URL
2953
+ *
2954
+ * @param options
2955
+ * @param event
2956
+ * @returns
2957
+ */
2958
+ async function pingWebhook(options, event = "charge.success") {
2959
+ const [command] = useCommand();
2960
+ let canProceed = false;
2961
+ try {
2962
+ canProceed = await refreshIntegration();
2963
+ } catch (e) {
2964
+ console.error(e);
2965
+ }
2966
+ let domain = "test";
2967
+ if (options.domain) domain = options.domain;
2968
+ if (options.event) event = options.event;
2969
+ const key = await getKeys(read("token"), "secret", domain);
2970
+ return new Promise((resolve, reject) => {
2971
+ if (!canProceed) return void command().error("ERROR: Unable to ping webhook URL");
2972
+ const eventObject = webhooks_default[event];
2973
+ if (eventObject) {
2974
+ const hash = crypto.default.createHmac("sha512", key).update(JSON.stringify(eventObject)).digest("hex");
2975
+ const uri = read("selected_integration")[domain + "_webhook_endpoint"];
2976
+ const spinner = (0, ora.default)(`Sending sample ${event} event payload to ${uri}`).start();
2977
+ axios_default.post(uri, eventObject, { headers: { "x-paystack-signature": hash } }).then((response) => {
2978
+ spinner.succeed(`Sample ${event} event payload sent to ${uri}`);
2979
+ resolve({
2980
+ code: response.status,
2981
+ text: response.statusText,
2982
+ data: response.data
2983
+ });
2984
+ }).catch((e) => {
2985
+ spinner.fail(`Failed to send sample ${event} event payload to ${uri}`);
2986
+ resolve({
2987
+ code: e.response?.status ?? 0,
2988
+ text: e.response?.statusText || "No response",
2989
+ data: typeof e.response?.data === "string" && e.response?.data?.includes("<html") ? { response: "HTML Response" } : e.response?.data || "No response data"
2990
+ });
2991
+ });
2992
+ } else {
2993
+ command().error("ERROR: Invalid event type - " + event);
2994
+ reject();
2995
+ }
2996
+ });
2997
+ }
2998
+ /**
2999
+ * Get integration
3000
+ *
3001
+ * @param id
3002
+ * @param token
3003
+ * @returns
3004
+ */
3005
+ function getIntegration(id, token) {
3006
+ const [command] = useCommand();
3007
+ const spinner = (0, ora.default)("getting integration").start();
3008
+ return new Promise((resolve, reject) => {
3009
+ axios_default.get("/integration/" + id, { headers: {
3010
+ Authorization: "Bearer " + token,
3011
+ "jwt-auth": true
3012
+ } }).then((response) => {
3013
+ resolve(response.data.data);
3014
+ }).catch((e) => {
3015
+ command().error(`ERROR: ${e}`);
3016
+ reject(e.response.data.message);
3017
+ }).finally(() => {
3018
+ spinner.stop();
3019
+ });
3020
+ });
3021
+ }
3022
+ /**
3023
+ * Sign in user
3024
+ *
3025
+ * @param email
3026
+ * @param password
3027
+ * @returns
3028
+ */
3029
+ async function signIn(email, password) {
3030
+ const [command] = useCommand();
3031
+ const spinner = (0, ora.default)("Logging in...").start();
3032
+ try {
3033
+ const { data: response } = await axios_default.post("/login", {
3034
+ email,
3035
+ password
3036
+ });
3037
+ if (response && response.data && !response.data.mfa_required) {
3038
+ spinner.succeed("Login successful");
3039
+ return response;
3040
+ } else if (response && response.data && response.data.mfa_required) {
3041
+ spinner.stop();
3042
+ const totp = await command().secret("Enter OTP or MFA code:", "*");
3043
+ spinner.start("Verifying MFA...");
3044
+ const [e, payload] = await promiseWrapper(verifyMfa(totp, response.data.token));
3045
+ if (payload && !e) {
3046
+ spinner.succeed("Login successful");
3047
+ return payload;
3048
+ } else spinner.fail(e ?? "MFA verification failed");
3049
+ } else spinner.fail("Login failed");
3050
+ } catch (e) {
3051
+ spinner.fail(e.response?.data?.message?.text || e.response?.data?.message || "Unable to sign in, please try again in a few minutes");
3052
+ }
3053
+ }
3054
+ /**
3055
+ * Verify MFA
3056
+ *
3057
+ * @param totp
3058
+ * @param token
3059
+ * @returns
3060
+ */
3061
+ function verifyMfa(totp, token) {
3062
+ return new Promise((resolve, reject) => {
3063
+ axios_default.post("/verify-mfa", { totp }, { headers: {
3064
+ Authorization: `Bearer ${token}`,
3065
+ "jwt-auth": true
3066
+ } }).then((response) => {
3067
+ resolve(response.data);
3068
+ }).catch(({ response }) => {
3069
+ reject(response.data.message || "Unable to verify MFA, please try again in a few minutes");
3070
+ });
3071
+ });
3072
+ }
3073
+ /**
3074
+ * Store login details
3075
+ *
3076
+ * @param payload
3077
+ */
3078
+ function storeLoginDetails(payload) {
3079
+ write("token", payload.data.token);
3080
+ write("token_expiry", payload.data.expiry);
3081
+ write("user", payload.data.user);
3082
+ }
3083
+ /**
3084
+ * Clear authentication details
3085
+ */
3086
+ function clearAuth() {
3087
+ remove("token");
3088
+ remove("token_expiry");
3089
+ remove("user");
3090
+ }
3091
+
3092
+ //#endregion
3093
+ //#region src/Commands/LoginCommand.ts
3094
+ var LoginCommand = class extends __h3ravel_musket.Command {
3095
+ signature = "login";
3096
+ description = "Log in to paystack cli";
3097
+ async handle() {
3098
+ const [_, setCommand] = useCommand();
3099
+ setCommand(this);
3100
+ let token, user;
3101
+ if (parseInt(read("token_expiry")) * 1e3 > parseFloat(Date.now().toString())) {
3102
+ token = read("token");
3103
+ user = read("user");
3104
+ this.info("You're already logged in");
3105
+ return;
3106
+ } else {
3107
+ const remembered = read("remember_login");
3108
+ const email = await this.ask("Email address", remembered ? remembered.email : void 0);
3109
+ const password = await this.secret("Password", "*");
3110
+ if (await this.confirm("Remember Email Address?", true)) write("remember_login", { email });
3111
+ else remove("remember_login");
3112
+ const [_$1, response] = await promiseWrapper(signIn(email, password));
3113
+ if (response && response.data) {
3114
+ storeLoginDetails(response);
3115
+ token = response.data.token;
3116
+ user = response.data.user;
3117
+ }
3118
+ }
3119
+ if (token && user) {
3120
+ const [err, integration] = await promiseWrapper(selectIntegration(user.integrations, token));
3121
+ if (err || !integration) this.error("ERROR: " + (err ?? "Integration selection failed")).newLine();
3122
+ else {
3123
+ write("selected_integration", integration);
3124
+ const user_role = read("selected_integration").logged_in_user_role;
3125
+ const [err$1, integrationData] = await promiseWrapper(getIntegration(integration.id, token));
3126
+ if (err$1 || !integrationData) return void this.error("ERROR: " + (err$1 ?? "Failed to fetch integration data")).newLine();
3127
+ integrationData.logged_in_user_role = user_role;
3128
+ write("selected_integration", integrationData);
3129
+ __h3ravel_shared.Logger.log([
3130
+ ["Logged in as", "white"],
3131
+ [user.email, "cyan"],
3132
+ ["-", "white"],
3133
+ [integration.business_name, "green"],
3134
+ ["(" + integration.id + ")", "white"]
3135
+ ], " ");
3136
+ this.newLine();
3137
+ }
3138
+ }
3139
+ }
3140
+ };
3141
+
3142
+ //#endregion
3143
+ //#region src/Commands/LogoutCommand.ts
3144
+ var LogoutCommand = class extends __h3ravel_musket.Command {
3145
+ signature = "logout";
3146
+ description = "Log out of paystack cli";
3147
+ async handle() {
3148
+ const [_, setCommand] = useCommand();
3149
+ setCommand(this);
3150
+ this.newLine();
3151
+ const spinner = (0, ora.default)("Logging out...").start();
3152
+ try {
3153
+ await wait(1e3, () => clearAuth());
3154
+ spinner.succeed("Logged out successfully");
3155
+ } catch (error) {
3156
+ spinner.fail("Logout failed");
3157
+ console.error("An error occurred during logout:", error);
3158
+ }
3159
+ this.newLine();
3160
+ }
3161
+ };
3162
+
3163
+ //#endregion
3164
+ //#region src/Commands/WebhookCommand.ts
3165
+ var WebhookCommand = class extends __h3ravel_musket.Command {
3166
+ signature = `webhook
3167
+ {command=listen : The command to run to listen for webhooks locally : [listen, ping]}
3168
+ {local_route? : Specify the local route to listen on for webhooks (only for listen command)}
3169
+ {--D|domain=test : Specify the domain to ping the webhook : [test, live]}
3170
+ {--F|forward? : Specify a URL to forward the webhook to instead of the saved webhook URL}
3171
+ {--E|event? : Specify the event type to simulate : [charge.success,transfer.success,transfer.failed,subscription.create]}
3172
+ `;
3173
+ description = "Listen for webhook events locally, runs a webhook endpoint health check and listens for incoming webhooks, and ping your webhook URL from the CLI.";
3174
+ async handle() {
3175
+ const [_, setCommand] = useCommand();
3176
+ const [getConfig] = useConfig();
3177
+ setCommand(this);
3178
+ this.newLine();
3179
+ const config = getConfig();
3180
+ let event = this.option("event");
3181
+ let local_route = this.argument("local_route");
3182
+ const selected_integration = read("selected_integration")?.id;
3183
+ const user = read("user")?.id;
3184
+ if (!selected_integration || !user) return void this.error("ERROR: You're not signed in, please run the `login` command before you begin");
3185
+ if (this.argument("command") == "listen" && !local_route) local_route = await this.ask("Enter the local route to listen on for webhooks: ", "http://localhost:8080/webhook");
3186
+ else if (this.argument("command") == "ping" && !event) event = await this.choice("Select event to simulate", [
3187
+ {
3188
+ name: "Charge Success",
3189
+ value: "charge.success"
3190
+ },
3191
+ {
3192
+ name: "Transfer Success",
3193
+ value: "transfer.success"
3194
+ },
3195
+ {
3196
+ name: "Transfer Failed",
3197
+ value: "transfer.failed"
3198
+ },
3199
+ {
3200
+ name: "Subscription Create",
3201
+ value: "subscription.create"
3202
+ }
3203
+ ], 0);
3204
+ const domain = this.option("domain", "test");
3205
+ const forward = this.option("forward") || null;
3206
+ if (this.argument("command") == "listen") {
3207
+ const token = read("token");
3208
+ if (parseInt(read("token_expiry")) * 1e3 < parseFloat(Date.now().toString())) {
3209
+ this.error("ERROR: Your session has expired. Please run the `login` command to sign in again.");
3210
+ return;
3211
+ }
3212
+ const url = parseURL(local_route);
3213
+ if (!url.port) url.port = "8000";
3214
+ if (!url.search || url.search == "?") url.search = "";
3215
+ try {
3216
+ await __ngrok_ngrok.default.kill();
3217
+ } catch {
3218
+ this.debug("No existing ngrok process found to kill.");
3219
+ }
3220
+ const ngrokURL = (await __ngrok_ngrok.default.forward({
3221
+ addr: url.port,
3222
+ authtoken: config.ngrokAuthToken || process.env.NGROK_AUTH_TOKEN,
3223
+ domain: process.env.NGROK_DOMAIN
3224
+ })).url();
3225
+ const domain$1 = this.option("domain", "test");
3226
+ const spinner = (0, ora.default)("Tunelling webhook events to " + logger(local_route)).start();
3227
+ const [err, result] = await promiseWrapper(setWebhook(ngrokURL, token, read("selected_integration").id));
3228
+ if (err || !result) return void this.error("ERROR: " + (err ?? "Failed to set webhook URL")).newLine();
3229
+ spinner.succeed("Listening for incoming webhook events at " + logger(local_route));
3230
+ this.newLine().success(`INFO: Press ${logger("Ctrl+C", ["grey", "italic"])} to stop listening for webhook events.`).success(`INFO: Webhook URL set to ${logger(ngrokURL)} for ${domain$1} domain`).newLine();
3231
+ process.stdin.resume();
3232
+ } else if (this.argument("command") == "ping") {
3233
+ await promiseWrapper(refreshIntegration());
3234
+ const [e, response] = await promiseWrapper(pingWebhook({
3235
+ ...this.options(),
3236
+ domain,
3237
+ forward
3238
+ }, event));
3239
+ if (e || !response) return void this.error("ERROR: " + (e ?? "Failed to ping webhook URL.")).newLine();
3240
+ this.newLine().info(response.code + " - " + response.text).newLine();
3241
+ if (isJson(response.data)) dataRenderer(response.data);
3242
+ else dataRenderer({ body: response.data });
3243
+ } else this.error("ERROR: Invalid command. Please use either \"listen\" or \"ping\".").newLine();
3244
+ }
3245
+ };
3246
+
3247
+ //#endregion
3248
+ //#region src/logo.ts
3249
+ var logo_default = `
3250
+ ▄▖ ▗ ▌ ▄▖▖ ▄▖
3251
+ ▙▌▀▌▌▌▛▘▜▘▀▌▛▘▙▘ ▌ ▌ ▐
3252
+ ▌ █▌▙▌▄▌▐▖█▌▙▖▛▖ ▙▖▙▖▟▖
3253
+ ▄▌
3254
+ `;
3255
+
3256
+ //#endregion
3257
+ //#region src/cli.ts
3258
+ var Application = class {};
3259
+ initAxios();
3260
+ __h3ravel_musket.Kernel.init(new Application(), {
3261
+ logo: logo_default,
3262
+ exceptionHandler(exception) {
3263
+ const [getConfig] = useConfig();
3264
+ const config = getConfig();
3265
+ console.error(config.debug ? exception : exception.message);
3266
+ },
3267
+ baseCommands: [
3268
+ InitCommand,
3269
+ LoginCommand,
3270
+ LogoutCommand,
3271
+ ConfigCommand,
3272
+ WebhookCommand,
3273
+ ...Commands_default()
3274
+ ]
3275
+ });
3276
+
3277
+ //#endregion