@paybetaby/node-sdk 0.1.1

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.
@@ -0,0 +1,437 @@
1
+ interface HttpClientConfig {
2
+ apiKey: string;
3
+ baseUrl: string;
4
+ timeout: number;
5
+ }
6
+ declare class HttpClient {
7
+ private readonly config;
8
+ constructor(config: HttpClientConfig);
9
+ request<T>(method: string, path: string, options?: {
10
+ body?: unknown;
11
+ query?: Record<string, string | number | boolean | undefined | null>;
12
+ }): Promise<T>;
13
+ get<T>(path: string, query?: Record<string, string | number | boolean | undefined | null>): Promise<T>;
14
+ post<T>(path: string, body?: unknown): Promise<T>;
15
+ patch<T>(path: string, body?: unknown): Promise<T>;
16
+ delete<T>(path: string): Promise<T>;
17
+ }
18
+
19
+ type TransactionStatus = 'INITIATED' | 'FUNDED' | 'IN_ESCROW' | 'RELEASED' | 'DISPUTED' | 'REFUNDED';
20
+ interface Transaction {
21
+ id: string;
22
+ merchantId: string;
23
+ buyerEmail: string;
24
+ sellerEmail: string;
25
+ amount: number;
26
+ currency: string;
27
+ status: TransactionStatus;
28
+ metadata?: Record<string, unknown>;
29
+ disputeToken?: string;
30
+ paymentLinkToken?: string;
31
+ paymentLinkUrl?: string;
32
+ sagaStatus?: string;
33
+ sagaFailureReason?: string;
34
+ sagaFailedStep?: string;
35
+ createdAt: string;
36
+ updatedAt: string;
37
+ version: number;
38
+ }
39
+ interface CreateTransactionParams {
40
+ merchantId: string;
41
+ buyerEmail: string;
42
+ /** E.164 phone number — required by the API as a guaranteed WhatsApp/SMS delivery channel. */
43
+ buyerPhone: string;
44
+ sellerEmail: string;
45
+ /** Decimal amount in the major currency unit (naira/dollars), unlike Payment.amount which is minor-unit. */
46
+ amount: number;
47
+ currency: string;
48
+ metadata?: Record<string, unknown>;
49
+ }
50
+ interface ListTransactionsParams {
51
+ merchantId?: string;
52
+ buyerEmail?: string;
53
+ status?: TransactionStatus;
54
+ limit?: number;
55
+ offset?: number;
56
+ }
57
+ interface TransactionEvent {
58
+ id: string;
59
+ transactionId: string;
60
+ eventType: string;
61
+ previousStatus?: TransactionStatus;
62
+ newStatus?: TransactionStatus;
63
+ metadata?: Record<string, unknown>;
64
+ occurredAt: string;
65
+ }
66
+
67
+ interface RequestOptions {
68
+ idempotencyKey?: string;
69
+ }
70
+
71
+ declare class TransactionsResource {
72
+ private readonly http;
73
+ constructor(http: HttpClient);
74
+ create(params: CreateTransactionParams, opts?: RequestOptions): Promise<Transaction>;
75
+ /**
76
+ * Lists transactions. The bare `/transactions` endpoint is platform-role
77
+ * only — an API-key (merchant) caller gets a 403 there — so passing
78
+ * `merchantId` routes to `/transactions/merchant/:merchantId` instead.
79
+ */
80
+ list(params?: ListTransactionsParams): Promise<Transaction[]>;
81
+ retrieve(id: string): Promise<Transaction>;
82
+ listHistory(id: string): Promise<TransactionEvent[]>;
83
+ }
84
+
85
+ type PSPType = 'PAYSTACK' | 'FLUTTERWAVE' | 'BANK_DIRECT';
86
+ type PaymentMethod = 'CARD' | 'BANK_TRANSFER' | 'USSD' | 'MOBILE_MONEY' | 'BANK_ACCOUNT';
87
+ type PaymentStatus = 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'REFUNDED';
88
+ interface Payment {
89
+ id: string;
90
+ paymentId?: string;
91
+ merchantId: string;
92
+ transactionId: string;
93
+ amount: number;
94
+ currency: string;
95
+ status: PaymentStatus;
96
+ paymentMethod: PaymentMethod;
97
+ pspType: PSPType;
98
+ customerEmail: string;
99
+ customerName?: string;
100
+ pspReference?: string;
101
+ authorizationUrl?: string;
102
+ paymentLinkToken?: string;
103
+ paymentLinkUrl?: string;
104
+ failureReason?: string;
105
+ metadata?: Record<string, unknown>;
106
+ createdAt: string;
107
+ completedAt?: string;
108
+ /** Number of PSP attempts recorded for this payment. */
109
+ attemptsCount: number;
110
+ }
111
+ interface PaymentAttempt {
112
+ id: string;
113
+ paymentId: string;
114
+ attemptNumber: number;
115
+ status: PaymentStatus;
116
+ pspReference?: string;
117
+ failureReason?: string;
118
+ attemptedAt: string;
119
+ }
120
+ interface InitiatePaymentParams {
121
+ merchantId: string;
122
+ transactionId: string;
123
+ /** Integer amount in the smallest currency unit (kobo for NGN, cents for USD) — not a decimal. */
124
+ amount: number;
125
+ currency: string;
126
+ paymentMethod: PaymentMethod;
127
+ pspType: PSPType;
128
+ customerEmail: string;
129
+ customerName?: string;
130
+ idempotencyKey?: string;
131
+ redirectUrl?: string;
132
+ metadata?: Record<string, unknown>;
133
+ }
134
+ interface ListPaymentsParams {
135
+ merchantId?: string;
136
+ limit?: number;
137
+ offset?: number;
138
+ }
139
+
140
+ declare class PaymentsResource {
141
+ private readonly http;
142
+ constructor(http: HttpClient);
143
+ initiate(params: InitiatePaymentParams): Promise<Payment>;
144
+ /**
145
+ * Lists payments. The bare `/payments` endpoint is platform-role only —
146
+ * an API-key (merchant) caller gets a 403 there — so passing `merchantId`
147
+ * (which every merchant API key call needs) routes to
148
+ * `/payments/merchant/:merchantId` instead, matching what the API
149
+ * actually allows a merchant credential to call.
150
+ */
151
+ list(params?: ListPaymentsParams): Promise<Payment[]>;
152
+ retrieve(id: string): Promise<Payment>;
153
+ verify(id: string): Promise<Payment>;
154
+ retry(id: string): Promise<Payment>;
155
+ listAttempts(id: string): Promise<PaymentAttempt[]>;
156
+ }
157
+
158
+ type EscrowStatus = 'created' | 'funded' | 'pending_release' | 'released' | 'disputed' | 'refunded' | 'cancelled';
159
+ type ConditionType = 'DELIVERY_CONFIRMATION' | 'BUYER_CONFIRMATION' | 'TIME_BASED' | 'MANUAL_APPROVAL';
160
+ type ConditionLogic = 'AND' | 'OR';
161
+ interface ReleaseCondition {
162
+ type: ConditionType;
163
+ config?: Record<string, unknown>;
164
+ isMet: boolean;
165
+ metAt?: string;
166
+ }
167
+ interface ReleasePolicy {
168
+ logic: ConditionLogic;
169
+ conditions: Array<{
170
+ type: ConditionType;
171
+ config?: Record<string, unknown>;
172
+ }>;
173
+ }
174
+ interface EscrowBalance {
175
+ escrowId: string;
176
+ heldAmount: string;
177
+ releasedAmount: string;
178
+ refundedAmount: string;
179
+ currency: string;
180
+ }
181
+ interface Escrow {
182
+ id: string;
183
+ transactionId: string;
184
+ merchantId: string;
185
+ buyerEmail: string;
186
+ sellerEmail: string;
187
+ /** Integer amount in kobo — the API does not divide this down to a decimal on the way out, unlike on create. */
188
+ amount: number;
189
+ currency: string;
190
+ status: EscrowStatus;
191
+ releasePolicy: ReleasePolicy | null;
192
+ createdAt: string | null;
193
+ updatedAt: string | null;
194
+ /** Only present on GET /escrows/:id. */
195
+ deliveryTrackingReference?: string | null;
196
+ }
197
+ interface CreateEscrowConditionParams {
198
+ type: ConditionType;
199
+ config?: Record<string, unknown>;
200
+ }
201
+ interface CreateEscrowReleasePolicyParams {
202
+ conditionLogic?: ConditionLogic;
203
+ conditions?: CreateEscrowConditionParams[];
204
+ }
205
+ interface CreateEscrowParams {
206
+ transactionId: string;
207
+ merchantId: string;
208
+ buyerEmail: string;
209
+ /** E.164 phone number — required by the API as a guaranteed WhatsApp/SMS delivery channel. */
210
+ buyerPhone: string;
211
+ sellerEmail: string;
212
+ /** Decimal amount in the major currency unit (naira/dollars) — the API converts to kobo itself. */
213
+ amount: number;
214
+ currency: string;
215
+ releasePolicy?: CreateEscrowReleasePolicyParams;
216
+ idempotencyKey?: string;
217
+ }
218
+ interface ListEscrowsParams {
219
+ merchantId?: string;
220
+ status?: EscrowStatus;
221
+ limit?: number;
222
+ offset?: number;
223
+ }
224
+ interface EscrowConditionsResponse {
225
+ escrowId: string;
226
+ logic: ConditionLogic;
227
+ canRelease: boolean;
228
+ conditions: ReleaseCondition[];
229
+ }
230
+ interface EscrowListResponse {
231
+ escrows: Escrow[];
232
+ total: number;
233
+ limit: number;
234
+ offset: number;
235
+ }
236
+ interface ReleaseEscrowParams {
237
+ /** Ignored if supplied — actorId/actorType come from the caller's own session, never the request body, per the API's audit-trail design. Kept optional for forward-compat only. */
238
+ actorId?: string;
239
+ actorType?: string;
240
+ idempotencyKey?: string;
241
+ }
242
+ interface ConfirmDeliveryParams {
243
+ actorId?: string;
244
+ idempotencyKey?: string;
245
+ trackingReference?: string;
246
+ }
247
+ interface ConfirmBuyerParams {
248
+ actorId?: string;
249
+ idempotencyKey?: string;
250
+ }
251
+
252
+ declare class EscrowsResource {
253
+ private readonly http;
254
+ constructor(http: HttpClient);
255
+ create(params: CreateEscrowParams, opts?: RequestOptions): Promise<Escrow>;
256
+ /**
257
+ * Lists escrows. The bare `/escrows` endpoint is platform-role only — an
258
+ * API-key (merchant) caller gets a 403 there — so passing `merchantId`
259
+ * routes to `/escrows/merchant/:merchantId` instead. Unlike
260
+ * payments/transactions/disputes, this returns a `{ escrows, total,
261
+ * limit, offset }` envelope rather than a bare array.
262
+ */
263
+ list(params?: ListEscrowsParams): Promise<EscrowListResponse>;
264
+ retrieve(id: string): Promise<Escrow>;
265
+ retrieveBalance(id: string): Promise<EscrowBalance>;
266
+ retrieveConditions(id: string): Promise<EscrowConditionsResponse>;
267
+ release(id: string, params?: ReleaseEscrowParams): Promise<Escrow>;
268
+ refund(id: string): Promise<Escrow>;
269
+ dispute(id: string): Promise<Escrow>;
270
+ cancel(id: string): Promise<Escrow>;
271
+ confirmDelivery(id: string, params?: ConfirmDeliveryParams): Promise<Escrow>;
272
+ confirmBuyer(id: string, params?: ConfirmBuyerParams): Promise<Escrow>;
273
+ }
274
+
275
+ type DisputeStatus = 'OPENED' | 'EVIDENCE_COLLECTION' | 'UNDER_REVIEW' | 'ARBITRATION' | 'RESOLVED' | 'CLOSED' | 'CANCELLED';
276
+ type DisputeStage = 'INITIAL_REVIEW' | 'EVIDENCE_REVIEW' | 'MERCHANT_RESPONSE' | 'BUYER_RESPONSE' | 'ARBITRATOR_REVIEW' | 'ESCALATION' | 'FINAL_DECISION';
277
+ type DisputeType = 'BUYER_COMPLAINT' | 'SELLER_COMPLAINT' | 'QUALITY_ISSUE' | 'NON_DELIVERY' | 'WRONG_ITEM' | 'DAMAGED_ITEM' | 'FRAUD' | 'OTHER';
278
+ type DisputePriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT';
279
+ type OpenedBy = 'BUYER' | 'SELLER';
280
+ type ResolutionOutcome = 'BUYER_WINS' | 'SELLER_WINS' | 'PARTIAL_REFUND' | 'PARTIAL_RELEASE' | 'SPLIT' | 'CANCELLED';
281
+ type EvidenceType = 'IMAGE' | 'DOCUMENT' | 'VIDEO' | 'OTHER';
282
+ type UploadedBy = 'BUYER' | 'SELLER' | 'ARBITRATOR';
283
+ interface Evidence {
284
+ id: string;
285
+ disputeId: string;
286
+ evidenceType: EvidenceType;
287
+ uploadedBy: UploadedBy;
288
+ description?: string;
289
+ fileName: string;
290
+ mimeType: string;
291
+ createdAt: string;
292
+ }
293
+ interface Dispute {
294
+ id: string;
295
+ transactionId: string;
296
+ escrowId: string;
297
+ merchantId: string;
298
+ buyerEmail: string;
299
+ sellerEmail: string;
300
+ disputeType: DisputeType;
301
+ priority: DisputePriority;
302
+ status: DisputeStatus;
303
+ currentStage: DisputeStage;
304
+ description: string;
305
+ amount: number;
306
+ currency: string;
307
+ openedBy: OpenedBy;
308
+ openedAt: string;
309
+ resolvedAt?: string;
310
+ resolutionOutcome?: ResolutionOutcome;
311
+ resolutionNotes?: string;
312
+ workflowId?: string;
313
+ assignedArbitratorId?: string;
314
+ createdAt: string;
315
+ updatedAt: string;
316
+ version: number;
317
+ }
318
+ interface OpenDisputeParams {
319
+ transactionId: string;
320
+ escrowId: string;
321
+ merchantId: string;
322
+ buyerEmail: string;
323
+ sellerEmail: string;
324
+ disputeType: DisputeType;
325
+ priority: DisputePriority;
326
+ description: string;
327
+ /** Integer amount in kobo. */
328
+ amount: number;
329
+ currency: string;
330
+ openedBy: OpenedBy;
331
+ workflowId?: string;
332
+ }
333
+ interface ListDisputesParams {
334
+ merchantId?: string;
335
+ status?: DisputeStatus;
336
+ stage?: DisputeStage;
337
+ limit?: number;
338
+ offset?: number;
339
+ }
340
+ interface UploadEvidenceParams {
341
+ evidenceType: EvidenceType;
342
+ uploadedBy: UploadedBy;
343
+ description?: string;
344
+ fileName: string;
345
+ /** Base64-encoded file content. */
346
+ fileData: string;
347
+ mimeType: string;
348
+ }
349
+ interface ResolveDisputeParams {
350
+ outcome: ResolutionOutcome;
351
+ notes: string;
352
+ }
353
+ interface CancelDisputeParams {
354
+ reason: string;
355
+ }
356
+
357
+ declare class DisputesResource {
358
+ private readonly http;
359
+ constructor(http: HttpClient);
360
+ open(params: OpenDisputeParams): Promise<Dispute>;
361
+ /**
362
+ * Lists disputes. The bare `/disputes` endpoint is platform-role only —
363
+ * an API-key (merchant) caller gets a 403 there — so passing
364
+ * `merchantId` routes to `/disputes/merchant/:merchantId` instead.
365
+ */
366
+ list(params?: ListDisputesParams): Promise<Dispute[]>;
367
+ retrieve(id: string): Promise<Dispute>;
368
+ listEvidence(id: string): Promise<Evidence[]>;
369
+ uploadEvidence(id: string, params: UploadEvidenceParams): Promise<Evidence>;
370
+ resolve(id: string, params: ResolveDisputeParams): Promise<Dispute>;
371
+ cancel(id: string, params: CancelDisputeParams): Promise<Dispute>;
372
+ }
373
+
374
+ type WebhookEventType = 'transaction.created' | 'transaction.funded' | 'transaction.escrowed' | 'transaction.released' | 'transaction.disputed' | 'transaction.refunded' | 'payment.received' | 'payment.failed' | 'dispute.opened' | 'dispute.resolved' | 'escrow.released';
375
+ interface WebhookEvent<T = unknown> {
376
+ id: string;
377
+ eventType: WebhookEventType;
378
+ timestamp: string;
379
+ data: T;
380
+ }
381
+ type TransactionWebhookEvent = WebhookEvent<Transaction>;
382
+ type PaymentWebhookEvent = WebhookEvent<Payment>;
383
+ type EscrowWebhookEvent = WebhookEvent<Escrow>;
384
+ type DisputeWebhookEvent = WebhookEvent<Dispute>;
385
+
386
+ declare class WebhooksResource {
387
+ private readonly secret;
388
+ constructor(secret: string);
389
+ /**
390
+ * Verifies the signature on an incoming webhook and parses the payload.
391
+ *
392
+ * PayBeta signs the concatenation of the delivery timestamp and the raw
393
+ * request body — `HMAC-SHA256(secret, "${timestamp}.${rawBody}")` — and
394
+ * sends the result hex-encoded, prefixed with `sha256=`, in the
395
+ * `X-PayBeta-Signature` header (see OutboundWebhookService). The
396
+ * timestamp itself arrives separately in `X-PayBeta-Timestamp`, so both
397
+ * headers are required here, not just the signature.
398
+ *
399
+ * Pass the raw request body (before JSON parsing), the value of the
400
+ * `X-PayBeta-Signature` header, and the value of the `X-PayBeta-Timestamp`
401
+ * header. Throws `PaybetaError` if the signature is invalid or the
402
+ * secret was not configured.
403
+ */
404
+ constructEvent<T = unknown>(rawBody: string | Buffer, signature: string, timestamp: string): WebhookEvent<T>;
405
+ }
406
+
407
+ interface PaybetaClientConfig {
408
+ /** API key obtained from the Paybeta dashboard (pb_live_* or pb_test_*) */
409
+ apiKey: string;
410
+ /** Override the default API base URL. Defaults to https://api.usepaybeta.com */
411
+ baseUrl?: string;
412
+ /** Webhook signing secret used to verify incoming webhook payloads */
413
+ webhookSecret?: string;
414
+ /** Request timeout in milliseconds. Defaults to 30000 */
415
+ timeout?: number;
416
+ }
417
+ declare class PaybetaClient {
418
+ readonly transactions: TransactionsResource;
419
+ readonly payments: PaymentsResource;
420
+ readonly escrows: EscrowsResource;
421
+ readonly disputes: DisputesResource;
422
+ readonly webhooks: WebhooksResource;
423
+ constructor(config: PaybetaClientConfig);
424
+ }
425
+
426
+ declare class PaybetaError extends Error {
427
+ constructor(message: string);
428
+ }
429
+ declare class PaybetaApiError extends PaybetaError {
430
+ readonly status: number;
431
+ readonly code: string;
432
+ readonly traceId: string;
433
+ readonly timestamp: string;
434
+ constructor(status: number, code: string, message: string, traceId: string, timestamp: string);
435
+ }
436
+
437
+ export { type CancelDisputeParams, type ConditionLogic, type ConditionType, type ConfirmBuyerParams, type ConfirmDeliveryParams, type CreateEscrowConditionParams, type CreateEscrowParams, type CreateEscrowReleasePolicyParams, type CreateTransactionParams, type Dispute, type DisputePriority, type DisputeStage, type DisputeStatus, type DisputeType, type DisputeWebhookEvent, type Escrow, type EscrowBalance, type EscrowConditionsResponse, type EscrowListResponse, type EscrowStatus, type EscrowWebhookEvent, type Evidence, type EvidenceType, type InitiatePaymentParams, type ListDisputesParams, type ListEscrowsParams, type ListPaymentsParams, type ListTransactionsParams, type OpenDisputeParams, type OpenedBy, type PSPType, PaybetaApiError, PaybetaClient, type PaybetaClientConfig, PaybetaError, type Payment, type PaymentAttempt, type PaymentMethod, type PaymentStatus, type PaymentWebhookEvent, type ReleaseCondition, type ReleaseEscrowParams, type ReleasePolicy, type RequestOptions, type ResolutionOutcome, type ResolveDisputeParams, type Transaction, type TransactionEvent, type TransactionStatus, type TransactionWebhookEvent, type UploadEvidenceParams, type UploadedBy, type WebhookEvent, type WebhookEventType };