@pabilo/sdk 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +424 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,8 +13,6 @@ TypeScript/JavaScript SDK for [pabilo.app](https://pabilo.app) — the Venezuela
|
|
|
13
13
|
npm install @pabilo/sdk
|
|
14
14
|
# or
|
|
15
15
|
pnpm add @pabilo/sdk
|
|
16
|
-
# or
|
|
17
|
-
yarn add @pabilo/sdk
|
|
18
16
|
```
|
|
19
17
|
|
|
20
18
|
## Quick start
|
|
@@ -25,31 +23,113 @@ import { PabiloClient } from '@pabilo/sdk';
|
|
|
25
23
|
const pabilo = new PabiloClient({ apiKey: 'YOUR_API_KEY' });
|
|
26
24
|
```
|
|
27
25
|
|
|
26
|
+
The client exposes four namespaces:
|
|
27
|
+
|
|
28
|
+
| Namespace | Description |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `pabilo.me` | Current user and plan info |
|
|
31
|
+
| `pabilo.bankAccounts` | Manage connected bank accounts |
|
|
32
|
+
| `pabilo.paymentLinks` | Create and manage payment links |
|
|
33
|
+
| `pabilo.payments` | Verify payments by bank reference |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## `pabilo.me`
|
|
38
|
+
|
|
39
|
+
### `me.getMe(): Promise<User>`
|
|
40
|
+
|
|
41
|
+
Returns the authenticated user's profile.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const user = await pabilo.me.getMe();
|
|
45
|
+
|
|
46
|
+
console.log(user.id); // string
|
|
47
|
+
console.log(user.email); // string | undefined
|
|
48
|
+
console.log(user.name); // string | undefined
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Returns:** `User`
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface User {
|
|
55
|
+
id: string;
|
|
56
|
+
email?: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### `me.getPlan(): Promise<Plan>`
|
|
64
|
+
|
|
65
|
+
Returns the current subscription plan for the authenticated account.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const plan = await pabilo.me.getPlan();
|
|
69
|
+
|
|
70
|
+
console.log(plan.name); // e.g. 'basic', 'pro'
|
|
71
|
+
console.log(plan.planType); // string | undefined
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Returns:** `Plan`
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
interface Plan {
|
|
78
|
+
name: string;
|
|
79
|
+
planType?: string;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
28
83
|
---
|
|
29
84
|
|
|
30
|
-
##
|
|
85
|
+
## `pabilo.bankAccounts`
|
|
31
86
|
|
|
32
|
-
###
|
|
87
|
+
### `bankAccounts.list(): Promise<UserBank[]>`
|
|
88
|
+
|
|
89
|
+
Returns all bank accounts connected to the authenticated user.
|
|
33
90
|
|
|
34
91
|
```typescript
|
|
35
92
|
const banks = await pabilo.bankAccounts.list();
|
|
36
93
|
|
|
37
94
|
for (const bank of banks) {
|
|
38
|
-
console.log(bank.id
|
|
39
|
-
|
|
95
|
+
console.log(bank.id); // MongoDB ObjectId string
|
|
96
|
+
console.log(bank.provider); // 'VE_BAN' | 'VE_BAN_EMP_V2' | 'BANK_TEST' | ...
|
|
97
|
+
console.log(bank.description); // display name set during creation
|
|
98
|
+
console.log(bank.bank_accounts); // BankAccountEntry[]
|
|
99
|
+
console.log(bank.to_trash); // boolean — true if soft-deleted
|
|
40
100
|
}
|
|
41
101
|
```
|
|
42
102
|
|
|
43
|
-
|
|
103
|
+
**Returns:** `UserBank[]`
|
|
44
104
|
|
|
45
|
-
|
|
105
|
+
```typescript
|
|
106
|
+
interface UserBank {
|
|
107
|
+
id: string;
|
|
108
|
+
description: string;
|
|
109
|
+
provider: string;
|
|
110
|
+
bank_accounts: BankAccountEntry[];
|
|
111
|
+
payment_link?: boolean;
|
|
112
|
+
to_trash?: boolean;
|
|
113
|
+
}
|
|
46
114
|
|
|
47
|
-
|
|
115
|
+
interface BankAccountEntry {
|
|
116
|
+
account_number: string;
|
|
117
|
+
account_type: string; // e.g. 'AHORRO', 'CORRIENTE'
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### `bankAccounts.create(req): Promise<UserBank>`
|
|
124
|
+
|
|
125
|
+
Creates a new bank account connection. Each provider has its own typed request — TypeScript enforces required fields per provider via a discriminated union on `bankProvider`.
|
|
126
|
+
|
|
127
|
+
**BDV personal — `VE_BAN`**
|
|
48
128
|
|
|
49
129
|
```typescript
|
|
50
130
|
const bank = await pabilo.bankAccounts.create({
|
|
51
131
|
bankProvider: 'VE_BAN',
|
|
52
|
-
description: 'Mi cuenta BDV',
|
|
132
|
+
description: 'Mi cuenta BDV personal',
|
|
53
133
|
userBankPhone: '04241234567',
|
|
54
134
|
userBankDni: '12345678',
|
|
55
135
|
username: 'usuario_portal_bdv',
|
|
@@ -59,7 +139,9 @@ const bank = await pabilo.bankAccounts.create({
|
|
|
59
139
|
console.log(bank.id); // use this id when creating payment links
|
|
60
140
|
```
|
|
61
141
|
|
|
62
|
-
**BDV empresa
|
|
142
|
+
**BDV empresa — `VE_BAN_EMP_V2`**
|
|
143
|
+
|
|
144
|
+
The `accountNumber` and `apiKey` fields are mapped to `username` and `password` in the API — the SDK exposes semantic names.
|
|
63
145
|
|
|
64
146
|
```typescript
|
|
65
147
|
const bank = await pabilo.bankAccounts.create({
|
|
@@ -67,7 +149,7 @@ const bank = await pabilo.bankAccounts.create({
|
|
|
67
149
|
description: 'Cuenta empresa BDV',
|
|
68
150
|
userBankPhone: '04241234567',
|
|
69
151
|
userBankDni: '12345678',
|
|
70
|
-
accountNumber: '
|
|
152
|
+
accountNumber: '01020000000000000000', // número de cuenta
|
|
71
153
|
apiKey: 'bdv_api_key_here',
|
|
72
154
|
metadata: [
|
|
73
155
|
{ key_name: 'SHOW_DATE_IN_GENERIC_MOVEMENTS', key_value: 'true' },
|
|
@@ -75,23 +157,70 @@ const bank = await pabilo.bankAccounts.create({
|
|
|
75
157
|
});
|
|
76
158
|
```
|
|
77
159
|
|
|
78
|
-
**Test bank
|
|
160
|
+
**Test bank — `BANK_TEST`**
|
|
161
|
+
|
|
162
|
+
A sandboxed bank for testing. Always has a payment with reference `67890` available.
|
|
79
163
|
|
|
80
164
|
```typescript
|
|
81
165
|
const bank = await pabilo.bankAccounts.create({ bankProvider: 'BANK_TEST' });
|
|
82
166
|
```
|
|
83
167
|
|
|
84
|
-
|
|
168
|
+
**Request types:**
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// Shared base (not needed for BANK_TEST)
|
|
172
|
+
interface BaseCreateUserBankRequest {
|
|
173
|
+
description: string;
|
|
174
|
+
userBankPhone: string;
|
|
175
|
+
userBankDni: string;
|
|
176
|
+
metadata?: UserBankMetadataEntry[]; // [{ key_name: string, key_value: string }]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface CreateVeBanRequest extends BaseCreateUserBankRequest {
|
|
180
|
+
bankProvider: 'VE_BAN';
|
|
181
|
+
username: string;
|
|
182
|
+
password: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface CreateVeBanEmpV2Request extends BaseCreateUserBankRequest {
|
|
186
|
+
bankProvider: 'VE_BAN_EMP_V2';
|
|
187
|
+
accountNumber: string;
|
|
188
|
+
apiKey: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
interface CreateBankTestRequest {
|
|
192
|
+
bankProvider: 'BANK_TEST';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
type CreateUserBankRequest =
|
|
196
|
+
| CreateVeBanRequest
|
|
197
|
+
| CreateVeBanEmpV2Request
|
|
198
|
+
| CreateBankTestRequest;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Returns:** `UserBank` (same shape as `list()` entries)
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### `bankAccounts.delete(id): Promise<void>`
|
|
206
|
+
|
|
207
|
+
Soft-deletes a bank account (moves it to trash). The bank no longer appears in `list()` results.
|
|
85
208
|
|
|
86
209
|
```typescript
|
|
87
210
|
await pabilo.bankAccounts.delete(bank.id);
|
|
88
211
|
```
|
|
89
212
|
|
|
213
|
+
| Parameter | Type | Description |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `id` | `string` | The `UserBank.id` to delete |
|
|
216
|
+
|
|
90
217
|
---
|
|
91
218
|
|
|
92
|
-
##
|
|
219
|
+
## `pabilo.paymentLinks`
|
|
93
220
|
|
|
94
|
-
###
|
|
221
|
+
### `paymentLinks.create(req): Promise<PaymentLink>`
|
|
222
|
+
|
|
223
|
+
Creates a new payment link that customers can use to pay via Pago Móvil.
|
|
95
224
|
|
|
96
225
|
```typescript
|
|
97
226
|
const link = await pabilo.paymentLinks.create({
|
|
@@ -99,118 +228,271 @@ const link = await pabilo.paymentLinks.create({
|
|
|
99
228
|
description: 'Orden #1234',
|
|
100
229
|
userBankId: bank.id,
|
|
101
230
|
// optional
|
|
231
|
+
name: 'Servicio mensual',
|
|
102
232
|
redirectUrl: 'https://myapp.com/gracias',
|
|
103
233
|
webhookUrl: 'https://myapp.com/webhook/pabilo',
|
|
104
234
|
notificationByWhatsapp: true,
|
|
105
|
-
name: 'Pago por servicio',
|
|
106
235
|
isUsd: false,
|
|
236
|
+
currency: 'VES',
|
|
107
237
|
});
|
|
108
238
|
|
|
109
|
-
console.log(link.url); // https://pabilo.app/pay/...
|
|
110
|
-
console.log(link.id);
|
|
111
|
-
console.log(link.status); // 'pending' | '
|
|
239
|
+
console.log(link.url); // https://pabilo.app/pay/... share this with the customer
|
|
240
|
+
console.log(link.id); // use for getInfo / isPaid / update
|
|
241
|
+
console.log(link.status); // 'pending' | 'active' | 'paid' | 'expired' | 'cancelled'
|
|
112
242
|
```
|
|
113
243
|
|
|
114
|
-
|
|
244
|
+
**Request fields:**
|
|
245
|
+
|
|
246
|
+
| Field | Type | Required | Description |
|
|
247
|
+
|---|---|---|---|
|
|
248
|
+
| `amount` | `number` | yes | Amount in the payment currency |
|
|
249
|
+
| `description` | `string` | yes | Internal description |
|
|
250
|
+
| `userBankId` | `string` | yes | ID of the bank account to receive payment |
|
|
251
|
+
| `name` | `string` | no | Customer-facing name shown on the payment page |
|
|
252
|
+
| `currency` | `string` | no | Defaults to `'VES'` |
|
|
253
|
+
| `isUsd` | `boolean` | no | Whether the amount is in USD |
|
|
254
|
+
| `redirectUrl` | `string` | no | URL to redirect after payment |
|
|
255
|
+
| `webhookUrl` | `string` | no | URL to receive payment event webhooks |
|
|
256
|
+
| `notificationByWhatsapp` | `boolean` | no | Send WhatsApp notification on payment |
|
|
257
|
+
| `metadata` | `Record<string, unknown>` | no | Arbitrary key/value data |
|
|
258
|
+
|
|
259
|
+
**Returns:** `PaymentLink`
|
|
115
260
|
|
|
116
261
|
```typescript
|
|
117
|
-
|
|
118
|
-
|
|
262
|
+
interface PaymentLink {
|
|
263
|
+
id: string;
|
|
264
|
+
url: string;
|
|
265
|
+
amount?: number;
|
|
266
|
+
status?: 'pending' | 'paid' | 'active' | 'expired' | 'cancelled';
|
|
267
|
+
type?: 'default' | 'fixed';
|
|
268
|
+
userId?: string;
|
|
269
|
+
name?: string;
|
|
270
|
+
description?: string;
|
|
271
|
+
isUsd?: boolean;
|
|
272
|
+
redirectUrl?: string;
|
|
273
|
+
webhookUrl?: string;
|
|
274
|
+
notificationByWhatsapp?: boolean;
|
|
275
|
+
expirationTime?: number;
|
|
276
|
+
paymentLinkOrigin?: string;
|
|
277
|
+
createdAt?: string;
|
|
278
|
+
updatedAt?: string;
|
|
279
|
+
}
|
|
119
280
|
```
|
|
120
281
|
|
|
121
|
-
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### `paymentLinks.getInfo(id): Promise<PaymentLink>`
|
|
285
|
+
|
|
286
|
+
Fetches current state of a payment link (status, amount, etc.).
|
|
122
287
|
|
|
123
288
|
```typescript
|
|
124
|
-
const
|
|
289
|
+
const link = await pabilo.paymentLinks.getInfo('69d0083b691af50b78e07921');
|
|
290
|
+
|
|
291
|
+
console.log(link.status); // 'paid'
|
|
292
|
+
console.log(link.amount); // 4000
|
|
293
|
+
console.log(link.createdAt); // ISO date string
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Parameter | Type | Description |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| `id` | `string` | The `PaymentLink.id` |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
### `paymentLinks.isPaid(id): Promise<boolean>`
|
|
303
|
+
|
|
304
|
+
Convenience method — returns `true` if the payment link's status is `'paid'`.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const paid = await pabilo.paymentLinks.isPaid('69d0083b691af50b78e07921');
|
|
308
|
+
|
|
125
309
|
if (paid) {
|
|
126
310
|
// fulfill the order
|
|
127
311
|
}
|
|
128
312
|
```
|
|
129
313
|
|
|
130
|
-
|
|
314
|
+
| Parameter | Type | Description |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| `id` | `string` | The `PaymentLink.id` |
|
|
317
|
+
|
|
318
|
+
> Internally calls `getInfo()` and checks `status === 'paid'`.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### `paymentLinks.update(id, req): Promise<PaymentLink>`
|
|
323
|
+
|
|
324
|
+
Updates a payment link's amount, description, redirect URL, or currency.
|
|
131
325
|
|
|
132
326
|
```typescript
|
|
133
|
-
const updated = await pabilo.paymentLinks.update(
|
|
327
|
+
const updated = await pabilo.paymentLinks.update('69d0083b691af50b78e07921', {
|
|
134
328
|
amount: 5000,
|
|
135
329
|
description: 'Orden actualizada',
|
|
330
|
+
redirectUrl: 'https://myapp.com/nueva-ruta',
|
|
331
|
+
currency: 'VES',
|
|
136
332
|
});
|
|
333
|
+
|
|
334
|
+
console.log(updated.amount); // 5000
|
|
137
335
|
```
|
|
138
336
|
|
|
337
|
+
**Request fields (all optional):**
|
|
338
|
+
|
|
339
|
+
| Field | Type | Description |
|
|
340
|
+
|---|---|---|
|
|
341
|
+
| `amount` | `number` | New amount |
|
|
342
|
+
| `description` | `string` | New description |
|
|
343
|
+
| `redirectUrl` | `string` | New redirect URL |
|
|
344
|
+
| `currency` | `string` | New currency code |
|
|
345
|
+
|
|
139
346
|
---
|
|
140
347
|
|
|
141
|
-
##
|
|
348
|
+
## `pabilo.payments`
|
|
349
|
+
|
|
350
|
+
### `payments.verify(userBankId, req): Promise<VerifyPaymentResult>`
|
|
142
351
|
|
|
143
|
-
Used to confirm that a
|
|
352
|
+
Checks whether a specific bank transfer exists in a connected bank account. Used to confirm that a customer's Pago Móvil transfer matches an expected payment.
|
|
144
353
|
|
|
145
354
|
```typescript
|
|
146
|
-
const result = await pabilo.payments.verify(
|
|
355
|
+
const result = await pabilo.payments.verify(bank.id, {
|
|
147
356
|
amount: 4000,
|
|
148
357
|
bankReference: '12345678',
|
|
149
|
-
movementType: 'GENERIC', // optional
|
|
358
|
+
movementType: 'GENERIC', // optional, defaults to 'GENERIC'
|
|
150
359
|
});
|
|
151
360
|
|
|
152
361
|
if (result.found) {
|
|
153
|
-
console.log(
|
|
154
|
-
console.log(result.isNew); // true if first time seen
|
|
362
|
+
console.log(result.isNew); // true if first time this reference was seen
|
|
155
363
|
console.log(result.data.credit_cost);
|
|
156
|
-
console.log(result.data.
|
|
364
|
+
console.log(result.data.is_new);
|
|
365
|
+
|
|
366
|
+
const payment = result.data.user_bank_payment;
|
|
367
|
+
if (payment) {
|
|
368
|
+
console.log(payment.id);
|
|
369
|
+
console.log(payment.amount);
|
|
370
|
+
console.log(payment.status); // 'paid'
|
|
371
|
+
console.log(payment.bank_reference_id);
|
|
372
|
+
console.log(payment.payment_params.fecha_pago);
|
|
373
|
+
console.log(payment.payment_params.banco_origen);
|
|
374
|
+
console.log(payment.payment_params.telefono_pagador);
|
|
375
|
+
}
|
|
157
376
|
} else {
|
|
158
377
|
// result.reason → 'BANK_NOT_AVAILABLE' | 'PAYMENT_NOT_FOUND'
|
|
159
|
-
|
|
378
|
+
if (result.reason === 'BANK_NOT_AVAILABLE') {
|
|
379
|
+
// bank is offline or credentials expired
|
|
380
|
+
}
|
|
381
|
+
if (result.reason === 'PAYMENT_NOT_FOUND') {
|
|
382
|
+
// transfer does not exist or does not match
|
|
383
|
+
}
|
|
160
384
|
}
|
|
161
385
|
```
|
|
162
386
|
|
|
163
|
-
|
|
387
|
+
**Request fields:**
|
|
388
|
+
|
|
389
|
+
| Field | Type | Required | Description |
|
|
390
|
+
|---|---|---|---|
|
|
391
|
+
| `userBankId` (first arg) | `string` | yes | ID of the bank account to search |
|
|
392
|
+
| `amount` | `number` | yes | Expected transfer amount |
|
|
393
|
+
| `bankReference` | `string` | yes | Bank transfer reference number |
|
|
394
|
+
| `movementType` | `string` | no | Defaults to `'GENERIC'` |
|
|
395
|
+
|
|
396
|
+
**Returns:** `VerifyPaymentResult` — a discriminated union on `found`:
|
|
164
397
|
|
|
165
398
|
```typescript
|
|
166
399
|
type VerifyPaymentResult =
|
|
167
400
|
| { found: false; reason: 'BANK_NOT_AVAILABLE' | 'PAYMENT_NOT_FOUND' }
|
|
168
401
|
| { found: true; isNew: boolean; data: PaymentData };
|
|
402
|
+
|
|
403
|
+
interface PaymentData {
|
|
404
|
+
is_new: boolean;
|
|
405
|
+
credit_cost: number;
|
|
406
|
+
user_bank_payment?: UserBankPayment;
|
|
407
|
+
user_credits_total?: number;
|
|
408
|
+
user_credits_total_in_usd?: number;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
interface UserBankPayment {
|
|
412
|
+
id: string;
|
|
413
|
+
amount: number;
|
|
414
|
+
status: string;
|
|
415
|
+
user_id: string;
|
|
416
|
+
user_bank_id: string;
|
|
417
|
+
bank_reference_id: string;
|
|
418
|
+
confirmed_status: boolean;
|
|
419
|
+
credit_cost: number;
|
|
420
|
+
created_at: string;
|
|
421
|
+
updated_at: string;
|
|
422
|
+
payment_params: {
|
|
423
|
+
amount: number;
|
|
424
|
+
cedula_pagador: string | null;
|
|
425
|
+
telefono_pagador: string;
|
|
426
|
+
fecha_pago: string;
|
|
427
|
+
banco_origen: string;
|
|
428
|
+
cuenta_pagador: string;
|
|
429
|
+
invoice_number: string;
|
|
430
|
+
movement_type: string;
|
|
431
|
+
};
|
|
432
|
+
}
|
|
169
433
|
```
|
|
170
434
|
|
|
435
|
+
> The API returns HTTP 200 for `BANK_NOT_AVAILABLE` and `PAYMENT_NOT_FOUND`. The SDK handles this transparently — these cases are never thrown as errors.
|
|
436
|
+
|
|
171
437
|
---
|
|
172
438
|
|
|
173
439
|
## Error handling
|
|
174
440
|
|
|
175
|
-
|
|
441
|
+
All methods throw `PabiloError` on API errors (non-2xx HTTP responses) or network failures.
|
|
176
442
|
|
|
177
443
|
```typescript
|
|
178
444
|
import { PabiloClient, PabiloError } from '@pabilo/sdk';
|
|
179
445
|
|
|
180
446
|
try {
|
|
181
|
-
await pabilo.paymentLinks.create({ ... });
|
|
447
|
+
const link = await pabilo.paymentLinks.create({ ... });
|
|
182
448
|
} catch (err) {
|
|
183
449
|
if (err instanceof PabiloError) {
|
|
184
|
-
console.error(err.code); //
|
|
450
|
+
console.error(err.code); // PabiloErrorCode string
|
|
185
451
|
console.error(err.message); // human-readable message from the API
|
|
186
452
|
console.error(err.raw); // raw API response body
|
|
453
|
+
console.error(err.status); // HTTP status code (if available)
|
|
187
454
|
}
|
|
188
455
|
}
|
|
189
456
|
```
|
|
190
457
|
|
|
191
|
-
Common error codes
|
|
458
|
+
**Common error codes:**
|
|
459
|
+
|
|
460
|
+
| Code | Description |
|
|
461
|
+
|---|---|
|
|
462
|
+
| `BAD_REQUEST` | Invalid request body or parameters |
|
|
463
|
+
| `UNAUTHORIZED` | API key is missing or invalid |
|
|
464
|
+
| `NOT_FOUND` | Resource not found |
|
|
465
|
+
| `USER_BANK_ALREADY_EXISTS` | Bank account is already connected |
|
|
466
|
+
| `INTERNAL_SERVER_ERROR` | API server error |
|
|
467
|
+
| `NETWORK_ERROR` | Request could not reach the API |
|
|
468
|
+
| `REQUEST_FAILED` | HTTP error with no specific code |
|
|
192
469
|
|
|
193
470
|
---
|
|
194
471
|
|
|
195
|
-
##
|
|
472
|
+
## Testing with BANK_TEST
|
|
196
473
|
|
|
197
|
-
|
|
474
|
+
Use `BANK_TEST` to test the full payment flow without connecting a real bank. It has a pre-configured payment with reference `67890`.
|
|
198
475
|
|
|
199
476
|
```typescript
|
|
200
|
-
|
|
477
|
+
// 1. Create test bank
|
|
478
|
+
const bank = await pabilo.bankAccounts.create({ bankProvider: 'BANK_TEST' });
|
|
201
479
|
|
|
202
|
-
//
|
|
203
|
-
const
|
|
480
|
+
// 2. Create a payment link using the test bank
|
|
481
|
+
const link = await pabilo.paymentLinks.create({
|
|
482
|
+
amount: 100,
|
|
483
|
+
description: 'Test payment',
|
|
484
|
+
userBankId: bank.id,
|
|
485
|
+
});
|
|
204
486
|
|
|
205
|
-
//
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
487
|
+
// 3. Verify the test payment reference
|
|
488
|
+
const result = await pabilo.payments.verify(bank.id, {
|
|
489
|
+
amount: 0,
|
|
490
|
+
bankReference: '67890',
|
|
209
491
|
});
|
|
492
|
+
// result.found === true
|
|
210
493
|
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
const pabilo = new PabiloClient({ apiKey: 'YOUR_API_KEY', httpClient: new MyHttpClient() });
|
|
494
|
+
// 4. Clean up
|
|
495
|
+
await pabilo.bankAccounts.delete(bank.id);
|
|
214
496
|
```
|
|
215
497
|
|
|
216
498
|
---
|
|
@@ -229,41 +511,120 @@ export const pabilo = new PabiloClient({
|
|
|
229
511
|
```typescript
|
|
230
512
|
// app/api/checkout/route.ts
|
|
231
513
|
import { pabilo } from '@/lib/pabilo';
|
|
514
|
+
import { PabiloError } from '@pabilo/sdk';
|
|
232
515
|
|
|
233
516
|
export async function POST(req: Request) {
|
|
234
517
|
const { bankId, amount } = await req.json();
|
|
235
518
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
519
|
+
try {
|
|
520
|
+
const link = await pabilo.paymentLinks.create({
|
|
521
|
+
amount,
|
|
522
|
+
description: 'Checkout',
|
|
523
|
+
userBankId: bankId,
|
|
524
|
+
redirectUrl: `${process.env.NEXT_PUBLIC_URL}/gracias`,
|
|
525
|
+
webhookUrl: `${process.env.NEXT_PUBLIC_URL}/api/webhook/pabilo`,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
return Response.json({ url: link.url, id: link.id });
|
|
529
|
+
} catch (err) {
|
|
530
|
+
if (err instanceof PabiloError) {
|
|
531
|
+
return Response.json({ error: err.message }, { status: 400 });
|
|
532
|
+
}
|
|
533
|
+
throw err;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
```typescript
|
|
539
|
+
// app/api/webhook/pabilo/route.ts — poll-based alternative to webhooks
|
|
540
|
+
import { pabilo } from '@/lib/pabilo';
|
|
243
541
|
|
|
244
|
-
|
|
542
|
+
export async function GET(req: Request) {
|
|
543
|
+
const { searchParams } = new URL(req.url);
|
|
544
|
+
const linkId = searchParams.get('linkId')!;
|
|
545
|
+
|
|
546
|
+
const paid = await pabilo.paymentLinks.isPaid(linkId);
|
|
547
|
+
return Response.json({ paid });
|
|
245
548
|
}
|
|
246
549
|
```
|
|
247
550
|
|
|
248
551
|
---
|
|
249
552
|
|
|
553
|
+
## Advanced: custom HTTP client
|
|
554
|
+
|
|
555
|
+
The SDK accepts an `IHttpClient` implementation for logging, retries, or proxying requests.
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
import { PabiloClient, FetchHttpClient, type IHttpClient, type RequestOptions } from '@pabilo/sdk';
|
|
559
|
+
|
|
560
|
+
class LoggingHttpClient extends FetchHttpClient {
|
|
561
|
+
async request<T>(opts: RequestOptions): Promise<T> {
|
|
562
|
+
console.log('[pabilo]', opts.method, opts.path);
|
|
563
|
+
return super.request<T>(opts);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const pabilo = new PabiloClient({
|
|
568
|
+
apiKey: 'YOUR_API_KEY',
|
|
569
|
+
httpClient: new LoggingHttpClient({ baseUrl: 'https://api.pabilo.app', apiKey: 'YOUR_API_KEY' }),
|
|
570
|
+
});
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Custom base URL (e.g. staging):
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
const pabilo = new PabiloClient({
|
|
577
|
+
apiKey: 'YOUR_API_KEY',
|
|
578
|
+
baseUrl: 'https://staging.api.pabilo.app',
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
250
584
|
## Types reference
|
|
251
585
|
|
|
252
586
|
```typescript
|
|
253
587
|
import type {
|
|
588
|
+
// Client
|
|
589
|
+
PabiloClientOptions,
|
|
590
|
+
|
|
591
|
+
// Resources
|
|
592
|
+
User,
|
|
593
|
+
Plan,
|
|
254
594
|
UserBank,
|
|
255
595
|
BankAccountEntry,
|
|
256
596
|
PaymentLink,
|
|
257
|
-
PaymentLinkStatus, // 'pending' | 'paid' | 'active' | 'expired' | 'cancelled'
|
|
258
|
-
PaymentLinkType, // 'default' | 'fixed'
|
|
259
|
-
VerifyPaymentResult,
|
|
260
597
|
PaymentData,
|
|
261
598
|
UserBankPayment,
|
|
599
|
+
PaymentParams,
|
|
600
|
+
|
|
601
|
+
// Requests
|
|
262
602
|
CreateUserBankRequest,
|
|
263
603
|
CreateVeBanRequest,
|
|
264
604
|
CreateVeBanEmpV2Request,
|
|
265
605
|
CreateBankTestRequest,
|
|
606
|
+
UserBankMetadataEntry,
|
|
607
|
+
CreatePaymentLinkRequest,
|
|
608
|
+
UpdatePaymentLinkRequest,
|
|
609
|
+
VerifyPaymentRequest,
|
|
610
|
+
|
|
611
|
+
// Results
|
|
612
|
+
VerifyPaymentResult,
|
|
613
|
+
|
|
614
|
+
// Enums / literals
|
|
615
|
+
PaymentLinkStatus, // 'pending' | 'paid' | 'active' | 'expired' | 'cancelled'
|
|
616
|
+
PaymentLinkType, // 'default' | 'fixed'
|
|
617
|
+
BankProvider,
|
|
618
|
+
AccountType,
|
|
266
619
|
PabiloErrorCode,
|
|
620
|
+
|
|
621
|
+
// Ports (for DI / testing)
|
|
622
|
+
IHttpClient,
|
|
623
|
+
RequestOptions,
|
|
624
|
+
IBankAccountsPort,
|
|
625
|
+
IPaymentLinksPort,
|
|
626
|
+
IPaymentsPort,
|
|
627
|
+
IMePort,
|
|
267
628
|
} from '@pabilo/sdk';
|
|
268
629
|
```
|
|
269
630
|
|