@pabilo/sdk 0.1.5 → 0.1.7

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 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,41 +23,168 @@ 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.username); // string | undefined
49
+ console.log(user.fullName); // string | undefined
50
+ console.log(user.companyName); // string | undefined
51
+ console.log(user.credits); // number | undefined
52
+ console.log(user.planIsActive);// boolean | undefined
53
+ console.log(user.isDemo); // boolean | undefined
54
+ console.log(user.userType); // 'user' | 'admin' | 'commerce' | ... | undefined
55
+ ```
56
+
57
+ **Returns:** `User`
58
+
59
+ ```typescript
60
+ interface User {
61
+ id: string;
62
+ email?: string;
63
+ username?: string;
64
+ fullName?: string;
65
+ companyName?: string;
66
+ credits?: number;
67
+ planIsActive?: boolean;
68
+ isDemo?: boolean;
69
+ userType?: UserType;
70
+ }
71
+
72
+ type UserType = 'system' | 'user' | 'admin' | 'test' | 'commerce' | string;
73
+ ```
74
+
28
75
  ---
29
76
 
30
- ## Bank accounts
77
+ ### `me.getPlan(): Promise<Plan>`
31
78
 
32
- ### List bank accounts
79
+ Returns the current subscription plan for the authenticated account.
80
+
81
+ ```typescript
82
+ const plan = await pabilo.me.getPlan();
83
+
84
+ console.log(plan.name); // e.g. 'Pro'
85
+ console.log(plan.planType); // 'credit' | 'unlimited' | 'counter'
86
+ console.log(plan.period); // 'month' | 'six_months' | 'year'
87
+ console.log(plan.requestLimit); // number (-1 = unlimited)
88
+ console.log(plan.bankAccountLimit); // number (-1 = unlimited)
89
+ console.log(plan.initialCredits); // number
90
+ console.log(plan.price); // number
91
+ console.log(plan.benefits); // PlanBenefit[]
92
+ ```
93
+
94
+ **Returns:** `Plan`
95
+
96
+ ```typescript
97
+ interface Plan {
98
+ id?: string;
99
+ name: string;
100
+ description?: string;
101
+ planType?: PlanType; // 'credit' | 'unlimited' | 'counter'
102
+ period?: PlanPeriod; // 'month' | 'six_months' | 'year'
103
+ price?: number;
104
+ requestLimit?: number;
105
+ bankAccountLimit?: number;
106
+ initialCredits?: number;
107
+ maxAcumulatedCredits?: number;
108
+ benefits?: PlanBenefit[];
109
+ salient?: boolean;
110
+ hidden?: boolean;
111
+ }
112
+
113
+ interface PlanBenefit {
114
+ description: string;
115
+ contain: boolean;
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## `pabilo.bankAccounts`
122
+
123
+ ### `bankAccounts.list(): Promise<UserBank[]>`
124
+
125
+ Returns all bank accounts connected to the authenticated user.
33
126
 
34
127
  ```typescript
35
128
  const banks = await pabilo.bankAccounts.list();
36
129
 
37
130
  for (const bank of banks) {
38
- console.log(bank.id, bank.provider, bank.description);
39
- // bank.bank_accounts BankAccountEntry[]
131
+ console.log(bank.id); // MongoDB ObjectId string
132
+ console.log(bank.provider); // 'VE_BAN' | 'VE_BAN_EMP_V2' | 'BANK_TEST' | ...
133
+ console.log(bank.description); // display name set during creation
134
+ console.log(bank.bank_accounts); // BankAccountEntry[]
135
+ console.log(bank.to_trash); // boolean — true if soft-deleted
136
+ }
137
+ ```
138
+
139
+ **Returns:** `UserBank[]`
140
+
141
+ ```typescript
142
+ interface UserBank {
143
+ id: string;
144
+ description: string;
145
+ provider: BankProvider;
146
+ bank_accounts: BankAccountEntry[];
147
+ payment_link?: boolean;
148
+ to_trash?: boolean;
149
+ }
150
+
151
+ interface BankAccountEntry {
152
+ account_number: string;
153
+ account_type: string; // e.g. 'AHORRO', 'CORRIENTE'
40
154
  }
155
+
156
+ type BankProvider =
157
+ | 'VE_BAN' // BDV personal
158
+ | 'VE_BAN_EMP' // BDV empresa v1
159
+ | 'VE_BAN_EMP_V2' // BDV empresa v2
160
+ | 'VE_PROV' // Provincial personal
161
+ | 'VE_PROV_EMP' // Provincial empresa
162
+ | 'MERCANTIL_EMP_V1' // Mercantil empresa
163
+ | 'MERCANTIL_EMP_TEST_V1' // Mercantil test
164
+ | 'BANK_TEST' // Sandbox
165
+ | string;
41
166
  ```
42
167
 
43
- ### Create a bank account
168
+ ---
169
+
170
+ ### `bankAccounts.create(req): Promise<UserBank>`
44
171
 
45
- Each provider has its own typed request shape — TypeScript will enforce the required fields.
172
+ 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`.
46
173
 
47
- **BDV personal (`VE_BAN`)**
174
+ **BDV personal `VE_BAN`**
48
175
 
49
176
  ```typescript
50
177
  const bank = await pabilo.bankAccounts.create({
51
178
  bankProvider: 'VE_BAN',
52
- description: 'Mi cuenta BDV',
179
+ description: 'Mi cuenta BDV personal',
53
180
  userBankPhone: '04241234567',
54
181
  userBankDni: '12345678',
55
182
  username: 'usuario_portal_bdv',
56
183
  password: 'contraseña_portal_bdv',
57
184
  });
58
-
59
- console.log(bank.id); // use this id when creating payment links
60
185
  ```
61
186
 
62
- **BDV empresa (`VE_BAN_EMP_V2`)**
187
+ **BDV empresa `VE_BAN_EMP_V2`**
63
188
 
64
189
  ```typescript
65
190
  const bank = await pabilo.bankAccounts.create({
@@ -67,7 +192,7 @@ const bank = await pabilo.bankAccounts.create({
67
192
  description: 'Cuenta empresa BDV',
68
193
  userBankPhone: '04241234567',
69
194
  userBankDni: '12345678',
70
- accountNumber: '0102000000000000000', // account number
195
+ accountNumber: '01020000000000000000',
71
196
  apiKey: 'bdv_api_key_here',
72
197
  metadata: [
73
198
  { key_name: 'SHOW_DATE_IN_GENERIC_MOVEMENTS', key_value: 'true' },
@@ -75,13 +200,19 @@ const bank = await pabilo.bankAccounts.create({
75
200
  });
76
201
  ```
77
202
 
78
- **Test bank (`BANK_TEST`)**
203
+ **Test bank `BANK_TEST`**
204
+
205
+ A sandboxed bank for testing. Always has a payment with reference `67890` available.
79
206
 
80
207
  ```typescript
81
208
  const bank = await pabilo.bankAccounts.create({ bankProvider: 'BANK_TEST' });
82
209
  ```
83
210
 
84
- ### Delete a bank account
211
+ ---
212
+
213
+ ### `bankAccounts.delete(id): Promise<void>`
214
+
215
+ Soft-deletes a bank account. The bank no longer appears in `list()` results.
85
216
 
86
217
  ```typescript
87
218
  await pabilo.bankAccounts.delete(bank.id);
@@ -89,9 +220,53 @@ await pabilo.bankAccounts.delete(bank.id);
89
220
 
90
221
  ---
91
222
 
92
- ## Payment links
223
+ ## `pabilo.paymentLinks`
224
+
225
+ ### `paymentLinks.list(req?): Promise<PaymentLinksPage>`
226
+
227
+ Returns a paginated list of the authenticated user's payment links.
93
228
 
94
- ### Create a payment link
229
+ ```typescript
230
+ const page = await pabilo.paymentLinks.list({
231
+ limit: 10,
232
+ page: 1,
233
+ status: 'pending', // filter by status
234
+ type: 'default', // filter by type
235
+ search: 'orden', // search by name/description
236
+ });
237
+
238
+ console.log(page.total); // total count
239
+ console.log(page.page); // current page
240
+ console.log(page.limit); // page size
241
+ console.log(page.items); // PaymentLink[]
242
+ ```
243
+
244
+ **Request fields (all optional):**
245
+
246
+ | Field | Type | Default | Description |
247
+ |---|---|---|---|
248
+ | `page` | `number` | `1` | Page number |
249
+ | `limit` | `number` | `10` | Items per page |
250
+ | `status` | `PaymentLinkStatus` | — | Filter by status |
251
+ | `type` | `PaymentLinkType` | — | Filter by type |
252
+ | `search` | `string` | — | Text search |
253
+
254
+ **Returns:** `PaymentLinksPage`
255
+
256
+ ```typescript
257
+ interface PaymentLinksPage {
258
+ items: PaymentLink[];
259
+ total: number;
260
+ page: number;
261
+ limit: number;
262
+ }
263
+ ```
264
+
265
+ ---
266
+
267
+ ### `paymentLinks.create(req): Promise<PaymentLink>`
268
+
269
+ Creates a new payment link that customers can use to pay via Pago Móvil.
95
270
 
96
271
  ```typescript
97
272
  const link = await pabilo.paymentLinks.create({
@@ -99,38 +274,102 @@ const link = await pabilo.paymentLinks.create({
99
274
  description: 'Orden #1234',
100
275
  userBankId: bank.id,
101
276
  // optional
277
+ name: 'Servicio mensual',
102
278
  redirectUrl: 'https://myapp.com/gracias',
103
279
  webhookUrl: 'https://myapp.com/webhook/pabilo',
104
280
  notificationByWhatsapp: true,
105
- name: 'Pago por servicio',
106
281
  isUsd: false,
282
+ currency: 'VES',
107
283
  });
108
284
 
109
285
  console.log(link.url); // https://pabilo.app/pay/...
110
286
  console.log(link.id);
111
- console.log(link.status); // 'pending' | 'paid' | 'active' | 'expired' | 'cancelled'
287
+ console.log(link.status); // 'pending' | 'active' | 'paid' | 'failed' | 'canceled' | 'expired' | 'stopped'
112
288
  ```
113
289
 
114
- ### Get payment link info
290
+ **Request fields:**
291
+
292
+ | Field | Type | Required | Description |
293
+ |---|---|---|---|
294
+ | `amount` | `number` | yes | Amount in the payment currency |
295
+ | `description` | `string` | yes | Internal description |
296
+ | `userBankId` | `string` | yes | ID of the bank account to receive payment |
297
+ | `name` | `string` | no | Customer-facing name shown on the payment page |
298
+ | `currency` | `string` | no | Defaults to `'VES'` |
299
+ | `isUsd` | `boolean` | no | Whether the amount is in USD |
300
+ | `redirectUrl` | `string` | no | URL to redirect after payment |
301
+ | `webhookUrl` | `string` | no | URL to receive payment event webhooks |
302
+ | `notificationByWhatsapp` | `boolean` | no | Send WhatsApp notification on payment |
303
+ | `metadata` | `Record<string, unknown>` | no | Arbitrary key/value data |
304
+
305
+ **Returns:** `PaymentLink`
115
306
 
116
307
  ```typescript
117
- const link = await pabilo.paymentLinks.getInfo(linkId);
118
- console.log(link.status, link.amount);
308
+ interface PaymentLink {
309
+ id: string;
310
+ url: string;
311
+ amount?: number;
312
+ status?: PaymentLinkStatus;
313
+ statusDetail?: string;
314
+ type?: PaymentLinkType;
315
+ userId?: string;
316
+ userBankId?: string;
317
+ withSubscriptionId?: string;
318
+ name?: string;
319
+ description?: string;
320
+ isUsd?: boolean;
321
+ redirectUrl?: string;
322
+ webhookUrl?: string;
323
+ webhookMethod?: string;
324
+ notificationByWhatsapp?: boolean;
325
+ expirationTime?: number;
326
+ paymentLinkOrigin?: PaymentLinkOrigin;
327
+ createdAt?: string;
328
+ updatedAt?: string;
329
+ }
330
+
331
+ type PaymentLinkStatus = 'pending' | 'active' | 'paid' | 'failed' | 'canceled' | 'expired' | 'stopped' | string;
332
+ type PaymentLinkType = 'default' | 'fixed' | 'subscription' | 'donation' | string;
333
+ type PaymentLinkOrigin = 'pabilo' | 'api' | string;
119
334
  ```
120
335
 
121
- ### Check if a payment link was paid
336
+ ---
337
+
338
+ ### `paymentLinks.getInfo(id): Promise<PaymentLink>`
339
+
340
+ Fetches current state of a payment link.
122
341
 
123
342
  ```typescript
124
- const paid = await pabilo.paymentLinks.isPaid(linkId);
343
+ const link = await pabilo.paymentLinks.getInfo('69d0083b691af50b78e07921');
344
+
345
+ console.log(link.status); // 'paid'
346
+ console.log(link.statusDetail); // string — reason for current status
347
+ console.log(link.amount);
348
+ console.log(link.createdAt);
349
+ ```
350
+
351
+ ---
352
+
353
+ ### `paymentLinks.isPaid(id): Promise<boolean>`
354
+
355
+ Returns `true` if the payment link's status is `'paid'`.
356
+
357
+ ```typescript
358
+ const paid = await pabilo.paymentLinks.isPaid(link.id);
359
+
125
360
  if (paid) {
126
361
  // fulfill the order
127
362
  }
128
363
  ```
129
364
 
130
- ### Update a payment link
365
+ ---
366
+
367
+ ### `paymentLinks.update(id, req): Promise<PaymentLink>`
368
+
369
+ Updates a payment link's amount or description.
131
370
 
132
371
  ```typescript
133
- const updated = await pabilo.paymentLinks.update(linkId, {
372
+ const updated = await pabilo.paymentLinks.update(link.id, {
134
373
  amount: 5000,
135
374
  description: 'Orden actualizada',
136
375
  });
@@ -138,29 +377,51 @@ const updated = await pabilo.paymentLinks.update(linkId, {
138
377
 
139
378
  ---
140
379
 
141
- ## Verify a payment by bank reference
380
+ ## `pabilo.payments`
142
381
 
143
- Used to confirm that a specific bank transfer exists and matches the expected amount.
382
+ ### `payments.verify(userBankId, req): Promise<VerifyPaymentResult>`
383
+
384
+ Checks whether a specific bank transfer exists in a connected bank account.
144
385
 
145
386
  ```typescript
146
- const result = await pabilo.payments.verify(userBankId, {
387
+ const result = await pabilo.payments.verify(bank.id, {
147
388
  amount: 4000,
148
389
  bankReference: '12345678',
149
- movementType: 'GENERIC', // optional
390
+ movementType: 'GENERIC', // 'GENERIC' | 'MOVIL_PAY' | 'TRANSFER' | 'C2P'
150
391
  });
151
392
 
152
393
  if (result.found) {
153
- console.log('Payment found!');
154
- console.log(result.isNew); // true if first time seen
394
+ console.log(result.isNew);
155
395
  console.log(result.data.credit_cost);
156
- console.log(result.data.user_bank_payment); // full payment object
396
+
397
+ const payment = result.data.user_bank_payment;
398
+ if (payment) {
399
+ console.log(payment.id);
400
+ console.log(payment.amount);
401
+ console.log(payment.status); // 'pending' | 'paid' | 'failed'
402
+ console.log(payment.bank_reference_id);
403
+ console.log(payment.payment_params.fecha_pago);
404
+ console.log(payment.payment_params.banco_origen);
405
+ console.log(payment.payment_params.telefono_pagador);
406
+ }
157
407
  } else {
158
408
  // result.reason → 'BANK_NOT_AVAILABLE' | 'PAYMENT_NOT_FOUND'
159
- console.log('Not found:', result.reason);
409
+ if (result.reason === 'BANK_NOT_AVAILABLE') {
410
+ // bank is offline or credentials expired
411
+ }
160
412
  }
161
413
  ```
162
414
 
163
- The result is a **discriminated union** on `found`:
415
+ **`movementType` values:**
416
+
417
+ | Value | Description |
418
+ |---|---|
419
+ | `'GENERIC'` | Default — any movement type (default) |
420
+ | `'MOVIL_PAY'` | Pago Móvil |
421
+ | `'TRANSFER'` | Bank transfer |
422
+ | `'C2P'` | Cuenta a Persona (C2P) |
423
+
424
+ **Returns:** `VerifyPaymentResult` — a discriminated union on `found`:
164
425
 
165
426
  ```typescript
166
427
  type VerifyPaymentResult =
@@ -168,49 +429,123 @@ type VerifyPaymentResult =
168
429
  | { found: true; isNew: boolean; data: PaymentData };
169
430
  ```
170
431
 
432
+ > 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.
433
+
434
+ ---
435
+
436
+ ## Webhooks
437
+
438
+ When a payment link is paid, the API sends a `POST` to the `webhookUrl` with the following payload. Import `PaymentLinkWebhookPayload` to type your webhook handler:
439
+
440
+ ```typescript
441
+ import type { PaymentLinkWebhookPayload } from '@pabilo/sdk';
442
+
443
+ // Next.js App Router
444
+ export async function POST(req: Request) {
445
+ const payload: PaymentLinkWebhookPayload = await req.json();
446
+
447
+ console.log(payload.payment_link_id);
448
+ console.log(payload.status); // 'paid'
449
+ console.log(payload.credit_balance);
450
+
451
+ const payment = payload.user_bank_payment;
452
+ if (payment) {
453
+ console.log(payment.amount);
454
+ console.log(payment.bank_reference_id);
455
+ console.log(payment.payment_params.fecha_pago);
456
+ }
457
+
458
+ return Response.json({ ok: true });
459
+ }
460
+ ```
461
+
462
+ **`PaymentLinkWebhookPayload` shape:**
463
+
464
+ ```typescript
465
+ interface PaymentLinkWebhookPayload {
466
+ id: string;
467
+ created_at: string;
468
+ updated_at: string;
469
+ payment_link_id: string;
470
+ status: PaymentLinkStatus;
471
+ payment_link?: PaymentLink;
472
+ user_bank_payment?: UserBankPayment;
473
+ credit_balance: number;
474
+ metadata: Array<{ key: string; value: string }>;
475
+ }
476
+ ```
477
+
171
478
  ---
172
479
 
173
480
  ## Error handling
174
481
 
175
- SDK methods throw `PabiloError` on API or network failures.
482
+ All methods throw `PabiloError` on API errors or network failures.
176
483
 
177
484
  ```typescript
178
485
  import { PabiloClient, PabiloError } from '@pabilo/sdk';
179
486
 
180
487
  try {
181
- await pabilo.paymentLinks.create({ ... });
488
+ const link = await pabilo.paymentLinks.create({ ... });
182
489
  } catch (err) {
183
490
  if (err instanceof PabiloError) {
184
- console.error(err.code); // 'BAD_REQUEST' | 'UNAUTHORIZED' | 'NOT_FOUND' | ...
185
- console.error(err.message); // human-readable message from the API
186
- console.error(err.raw); // raw API response body
491
+ console.error(err.code); // PabiloErrorCode string
492
+ console.error(err.message); // human-readable message from the API
493
+ console.error(err.statusCode); // HTTP status code
494
+ console.error(err.raw); // raw API response body
187
495
  }
188
496
  }
189
497
  ```
190
498
 
191
- Common error codes: `BAD_REQUEST`, `UNAUTHORIZED`, `NOT_FOUND`, `USER_BANK_ALREADY_EXISTS`, `INTERNAL_SERVER_ERROR`, `NETWORK_ERROR`.
499
+ **Common error codes:**
500
+
501
+ | Code | Description |
502
+ |---|---|
503
+ | `BAD_REQUEST` | Invalid request body or parameters |
504
+ | `UNAUTHORIZED` | API key is missing or invalid |
505
+ | `FORBIDDEN` | Action not permitted |
506
+ | `NOT_FOUND` | Resource not found |
507
+ | `USER_BANK_ALREADY_EXISTS` | Bank account is already connected |
508
+ | `USER_BANCK_BAD_PASSWORD` | Wrong bank portal credentials |
509
+ | `USER_BANCK_PASSWORD_EXPIRED` | Bank portal password expired |
510
+ | `NOT_ENOUGH_CREDITS` | Insufficient credits in the account |
511
+ | `PLAN_IS_NOT_ACTIVE` | Account plan is inactive |
512
+ | `REQUEST_LIMIT_REACHED` | Plan request limit exceeded |
513
+ | `BANK_ACCOUNT_LIMIT_REACHED` | Plan bank account limit exceeded |
514
+ | `BANK_NOT_AVAILABLE` | Bank is temporarily offline |
515
+ | `BANK_TEMPORARILY_INACTIVE` | Bank is temporarily disabled |
516
+ | `BANK_TOO_MANY_REQUESTS` | Rate limit from the bank |
517
+ | `PAYMENT_NOT_FOUND` | Transfer reference not found |
518
+ | `PAYMENT_ALREADY_EXISTS` | Transfer already verified |
519
+ | `INTERNAL_ERROR` | API server error |
520
+ | `NETWORK_ERROR` | Request could not reach the API |
192
521
 
193
522
  ---
194
523
 
195
- ## Custom HTTP client
524
+ ## Testing with BANK_TEST
196
525
 
197
- The SDK accepts an `IHttpClient` implementation for custom fetch behavior (retries, logging, etc.).
526
+ Use `BANK_TEST` to test the full payment flow without connecting a real bank. Reference `67890` always returns a found payment.
198
527
 
199
528
  ```typescript
200
- import { PabiloClient, FetchHttpClient, PabiloHttpClient } from '@pabilo/sdk';
529
+ // 1. Create test bank
530
+ const bank = await pabilo.bankAccounts.create({ bankProvider: 'BANK_TEST' });
201
531
 
202
- // Default uses globalThis.fetch
203
- const pabilo = new PabiloClient({ apiKey: 'YOUR_API_KEY' });
532
+ // 2. Create a payment link
533
+ const link = await pabilo.paymentLinks.create({
534
+ amount: 100,
535
+ description: 'Test payment',
536
+ userBankId: bank.id,
537
+ webhookUrl: 'https://myapp.com/webhook',
538
+ });
204
539
 
205
- // Custom base URL (e.g. for a proxy or staging environment)
206
- const pabilo = new PabiloClient({
207
- apiKey: 'YOUR_API_KEY',
208
- baseUrl: 'https://staging.api.pabilo.app',
540
+ // 3. Verify the test payment
541
+ const result = await pabilo.payments.verify(bank.id, {
542
+ amount: 0,
543
+ bankReference: '67890',
209
544
  });
545
+ // result.found === true
210
546
 
211
- // Bring your own HTTP client
212
- class MyHttpClient extends FetchHttpClient { /* override request() */ }
213
- const pabilo = new PabiloClient({ apiKey: 'YOUR_API_KEY', httpClient: new MyHttpClient() });
547
+ // 4. Clean up
548
+ await pabilo.bankAccounts.delete(bank.id);
214
549
  ```
215
550
 
216
551
  ---
@@ -229,20 +564,73 @@ export const pabilo = new PabiloClient({
229
564
  ```typescript
230
565
  // app/api/checkout/route.ts
231
566
  import { pabilo } from '@/lib/pabilo';
567
+ import { PabiloError } from '@pabilo/sdk';
232
568
 
233
569
  export async function POST(req: Request) {
234
570
  const { bankId, amount } = await req.json();
235
571
 
236
- const link = await pabilo.paymentLinks.create({
237
- amount,
238
- description: 'Checkout',
239
- userBankId: bankId,
240
- redirectUrl: `${process.env.NEXT_PUBLIC_URL}/gracias`,
241
- webhookUrl: `${process.env.NEXT_PUBLIC_URL}/api/webhook/pabilo`,
242
- });
572
+ try {
573
+ const link = await pabilo.paymentLinks.create({
574
+ amount,
575
+ description: 'Checkout',
576
+ userBankId: bankId,
577
+ redirectUrl: `${process.env.NEXT_PUBLIC_URL}/gracias`,
578
+ webhookUrl: `${process.env.NEXT_PUBLIC_URL}/api/webhook/pabilo`,
579
+ });
580
+
581
+ return Response.json({ url: link.url, id: link.id });
582
+ } catch (err) {
583
+ if (err instanceof PabiloError) {
584
+ return Response.json({ error: err.message }, { status: 400 });
585
+ }
586
+ throw err;
587
+ }
588
+ }
589
+ ```
590
+
591
+ ```typescript
592
+ // app/api/webhook/pabilo/route.ts
593
+ import type { PaymentLinkWebhookPayload } from '@pabilo/sdk';
594
+ import { pabilo } from '@/lib/pabilo';
595
+
596
+ export async function POST(req: Request) {
597
+ const payload: PaymentLinkWebhookPayload = await req.json();
598
+
599
+ if (payload.status === 'paid') {
600
+ // fulfill the order linked to payload.payment_link_id
601
+ }
602
+
603
+ return Response.json({ ok: true });
604
+ }
605
+ ```
606
+
607
+ ---
608
+
609
+ ## Advanced: custom HTTP client
610
+
611
+ ```typescript
612
+ import { PabiloClient, FetchHttpClient, type RequestOptions } from '@pabilo/sdk';
243
613
 
244
- return Response.json({ url: link.url, id: link.id });
614
+ class LoggingHttpClient extends FetchHttpClient {
615
+ async request<T>(opts: RequestOptions): Promise<T> {
616
+ console.log('[pabilo]', opts.method, opts.path);
617
+ return super.request<T>(opts);
618
+ }
245
619
  }
620
+
621
+ const pabilo = new PabiloClient({
622
+ apiKey: 'YOUR_API_KEY',
623
+ httpClient: new LoggingHttpClient(),
624
+ });
625
+ ```
626
+
627
+ Custom base URL:
628
+
629
+ ```typescript
630
+ const pabilo = new PabiloClient({
631
+ apiKey: 'YOUR_API_KEY',
632
+ baseUrl: 'https://staging.api.pabilo.app',
633
+ });
246
634
  ```
247
635
 
248
636
  ---
@@ -251,19 +639,56 @@ export async function POST(req: Request) {
251
639
 
252
640
  ```typescript
253
641
  import type {
642
+ // Client
643
+ PabiloClientOptions,
644
+
645
+ // Resources
646
+ User,
647
+ Plan,
648
+ PlanBenefit,
254
649
  UserBank,
255
650
  BankAccountEntry,
256
651
  PaymentLink,
257
- PaymentLinkStatus, // 'pending' | 'paid' | 'active' | 'expired' | 'cancelled'
258
- PaymentLinkType, // 'default' | 'fixed'
259
- VerifyPaymentResult,
652
+ PaymentLinksPage,
260
653
  PaymentData,
261
654
  UserBankPayment,
655
+ PaymentParams,
656
+
657
+ // Requests
262
658
  CreateUserBankRequest,
263
659
  CreateVeBanRequest,
264
660
  CreateVeBanEmpV2Request,
265
661
  CreateBankTestRequest,
662
+ UserBankMetadataEntry,
663
+ CreatePaymentLinkRequest,
664
+ UpdatePaymentLinkRequest,
665
+ ListPaymentLinksRequest,
666
+ VerifyPaymentRequest,
667
+
668
+ // Results & Webhooks
669
+ VerifyPaymentResult,
670
+ PaymentLinkWebhookPayload,
671
+
672
+ // Literals / enums
673
+ PaymentLinkStatus, // 'pending' | 'active' | 'paid' | 'failed' | 'canceled' | 'expired' | 'stopped'
674
+ PaymentLinkType, // 'default' | 'fixed' | 'subscription' | 'donation'
675
+ PaymentLinkOrigin, // 'pabilo' | 'api'
676
+ BankProvider, // 'VE_BAN' | 'VE_BAN_EMP_V2' | ...
677
+ MovementType, // 'GENERIC' | 'MOVIL_PAY' | 'TRANSFER' | 'C2P'
678
+ UserBankPaymentStatus,// 'pending' | 'paid' | 'failed'
679
+ UserType, // 'user' | 'admin' | 'commerce' | ...
680
+ PlanType, // 'credit' | 'unlimited' | 'counter'
681
+ PlanPeriod, // 'month' | 'six_months' | 'year'
682
+ AccountType,
266
683
  PabiloErrorCode,
684
+
685
+ // Ports (for DI / testing)
686
+ IHttpClient,
687
+ RequestOptions,
688
+ IBankAccountsPort,
689
+ IPaymentLinksPort,
690
+ IPaymentsPort,
691
+ IMePort,
267
692
  } from '@pabilo/sdk';
268
693
  ```
269
694