@garuhq/node 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -317,6 +317,299 @@ var Charges = class {
317
317
  }
318
318
  };
319
319
 
320
+ // src/resources/installment-plans.ts
321
+ var InstallmentPlans = class {
322
+ constructor(http) {
323
+ this.http = http;
324
+ }
325
+ http;
326
+ /**
327
+ * Sell a product as a carnê. Auto-attaches `X-Idempotency-Key` (UUIDv4 if
328
+ * you don't pass `idempotencyKey`), which matters more here than anywhere
329
+ * else in the API: this call registers a REAL boleto at the bank, so a
330
+ * blind retry can put two payable barcodes in one buyer's hands.
331
+ *
332
+ * @example
333
+ * const carne = await garu.installmentPlans.create({
334
+ * productId: '40381e8e-6ee7-4b8e-9393-766a6e2109d2',
335
+ * customerId: 4821,
336
+ * installments: 12
337
+ * });
338
+ * // A R$1.200 product at fator 1,30 bills R$130,00 a month:
339
+ * carne.totalScheduled; // 1560
340
+ * carne.installmentAmount; // 130
341
+ * carne.installmentsDetail?.[0]; // parcela 1, with its barcode
342
+ *
343
+ * @example
344
+ * // Attribute the sale to an affiliate. Fixed at sale time: every later
345
+ * // parcela inherits it, so omitting it pays them nothing for the whole
346
+ * // carnê. The affiliate must already be active on this product.
347
+ * await garu.installmentPlans.create({
348
+ * productId: '40381e8e-6ee7-4b8e-9393-766a6e2109d2',
349
+ * customerId: 4821,
350
+ * installments: 6,
351
+ * firstDueDate: '2026-10-05',
352
+ * affiliateId: 5
353
+ * });
354
+ */
355
+ async create(params) {
356
+ const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
357
+ const { idempotencyKey: _omit, ...body } = params;
358
+ return this.http.call(
359
+ (signal) => this.http.client.POST("/api/v1/installment-plans", {
360
+ body,
361
+ headers: { "X-Idempotency-Key": idempotencyKey },
362
+ signal
363
+ }).then((r) => r)
364
+ );
365
+ }
366
+ /**
367
+ * List carnês, newest first. `dueFrom`/`dueTo` filter on the FIRST
368
+ * parcela's due date, which is what identifies the plan; filtering on every
369
+ * parcela would return one carnê twelve times.
370
+ *
371
+ * @example
372
+ * const atRisk = await garu.installmentPlans.list({ status: 'defaulted' });
373
+ *
374
+ * @example
375
+ * const live = await garu.installmentPlans.list({
376
+ * status: ['active', 'pending_activation'],
377
+ * customerId: 4821,
378
+ * limit: 50
379
+ * });
380
+ */
381
+ async list(params = {}) {
382
+ const qs = new URLSearchParams();
383
+ if (params.page !== void 0) qs.set("page", String(params.page));
384
+ if (params.limit !== void 0) qs.set("limit", String(params.limit));
385
+ if (params.customerId !== void 0) qs.set("customerId", String(params.customerId));
386
+ if (params.productId) qs.set("productId", params.productId);
387
+ if (params.dueFrom) qs.set("dueFrom", params.dueFrom);
388
+ if (params.dueTo) qs.set("dueTo", params.dueTo);
389
+ if (params.status) {
390
+ const statuses = Array.isArray(params.status) ? params.status : [params.status];
391
+ for (const s of statuses) qs.append("status", s);
392
+ }
393
+ const query = qs.toString();
394
+ const url = `/api/v1/installment-plans${query ? `?${query}` : ""}`;
395
+ return this.http.call(
396
+ (signal) => this.http.client.GET(url, { signal }).then(
397
+ (r) => r
398
+ )
399
+ );
400
+ }
401
+ /**
402
+ * Retrieve one carnê with every parcela: due date, status, barcode line and
403
+ * boleto PDF.
404
+ *
405
+ * @example
406
+ * const carne = await garu.installmentPlans.get(uuid);
407
+ * const unpaid = carne.installmentsDetail?.filter((i) => i.status !== 'paid');
408
+ * carne.totalCollected; // what has actually cleared, not what was billed
409
+ */
410
+ async get(uuid) {
411
+ return this.http.call(
412
+ (signal) => this.http.client.GET(`/api/v1/installment-plans/${uuid}`, { signal }).then(
413
+ (r) => r
414
+ )
415
+ );
416
+ }
417
+ /**
418
+ * Issue a segunda via for one parcela, once the current slip has expired.
419
+ *
420
+ * A boleto stays payable at any bank until its due date plus five days, so
421
+ * Garu refuses while the old barcode is still live — two live barcodes for
422
+ * one parcela is how a buyer pays it twice. Once per parcela per day.
423
+ *
424
+ * @example
425
+ * const result = await garu.installmentPlans.reissueInstallment(uuid, 4);
426
+ * if (result.status === 'emitted') {
427
+ * send(result.installment!.boleto!.barcodeLine);
428
+ * }
429
+ */
430
+ async reissueInstallment(uuid, number) {
431
+ return this.http.call(
432
+ (signal) => this.http.client.POST(
433
+ `/api/v1/installment-plans/${uuid}/installments/${number}/reissue`,
434
+ { signal }
435
+ ).then((r) => r)
436
+ );
437
+ }
438
+ /**
439
+ * Move one parcela to a later date. Its siblings keep theirs — this
440
+ * postpones a payment, it does not restructure the carnê. A slip already
441
+ * emitted stays payable on its original date until it expires.
442
+ *
443
+ * @example
444
+ * await garu.installmentPlans.postponeInstallment(uuid, 4, {
445
+ * newDueDate: '2026-12-20'
446
+ * });
447
+ */
448
+ async postponeInstallment(uuid, number, params) {
449
+ return this.http.call(
450
+ (signal) => this.http.client.POST(
451
+ `/api/v1/installment-plans/${uuid}/installments/${number}/postpone`,
452
+ { body: params, signal }
453
+ ).then((r) => r)
454
+ );
455
+ }
456
+ /**
457
+ * Record a parcela as paid, for when the buyer paid the slip but the
458
+ * webhook never arrived.
459
+ *
460
+ * Garu asks the provider to confirm the charge really compensated before
461
+ * recording it, because this settles the transaction and pays affiliate and
462
+ * co-producer commissions. A provider outage refuses the action rather than
463
+ * trusting the assertion.
464
+ *
465
+ * @example
466
+ * const parcela = await garu.installmentPlans.markInstallmentPaid(uuid, 3);
467
+ * parcela.status; // 'paid'
468
+ */
469
+ async markInstallmentPaid(uuid, number) {
470
+ return this.http.call(
471
+ (signal) => this.http.client.POST(
472
+ `/api/v1/installment-plans/${uuid}/installments/${number}/mark-paid`,
473
+ { signal }
474
+ ).then((r) => r)
475
+ );
476
+ }
477
+ /**
478
+ * Cancel the carnê. Emission and reminders stop and open slips are
479
+ * cancelled at the provider.
480
+ *
481
+ * Money already collected is NOT returned — open a refund request for that.
482
+ * A cancelled carnê is never revived by a late payment; that money opens a
483
+ * refund request instead.
484
+ *
485
+ * @example
486
+ * await garu.installmentPlans.cancel(uuid, { note: 'Comprador desistiu' });
487
+ */
488
+ async cancel(uuid, params = {}) {
489
+ return this.http.call(
490
+ (signal) => this.http.client.POST(`/api/v1/installment-plans/${uuid}/cancel`, {
491
+ body: params,
492
+ signal
493
+ }).then((r) => r)
494
+ );
495
+ }
496
+ /**
497
+ * Ask for this carnê to be refunded.
498
+ *
499
+ * Garu does NOT move the money. A boleto cannot be reversed and the funds
500
+ * already settled to you, so this records the request and notifies your
501
+ * team. Transfer the money to the buyer yourself, then close it with
502
+ * `garu.refundRequests.confirm`.
503
+ *
504
+ * @example
505
+ * const request = await garu.installmentPlans.requestRefund(uuid, {
506
+ * reason: 'Produto não entregue'
507
+ * });
508
+ * request.status; // 'pending' — nothing has moved yet
509
+ * request.amount; // defaults to everything the carnê collected
510
+ */
511
+ async requestRefund(uuid, params = {}) {
512
+ return this.http.call(
513
+ (signal) => this.http.client.POST(`/api/v1/installment-plans/${uuid}/refund-requests`, {
514
+ body: params,
515
+ signal
516
+ }).then((r) => r)
517
+ );
518
+ }
519
+ };
520
+
521
+ // src/resources/refund-requests.ts
522
+ var RefundRequests = class {
523
+ constructor(http) {
524
+ this.http = http;
525
+ }
526
+ http;
527
+ /**
528
+ * List refund requests, newest first. Covers carnê and Pix/boleto alike.
529
+ *
530
+ * @example
531
+ * // Everything you still owe a buyer.
532
+ * const owed = await garu.refundRequests.list({ status: 'pending' });
533
+ * const total = owed.data.reduce((sum, r) => sum + r.amount, 0);
534
+ *
535
+ * @example
536
+ * const forThisCarne = await garu.refundRequests.list({ planId: carne.uuid });
537
+ */
538
+ async list(params = {}) {
539
+ const qs = new URLSearchParams();
540
+ if (params.page !== void 0) qs.set("page", String(params.page));
541
+ if (params.limit !== void 0) qs.set("limit", String(params.limit));
542
+ if (params.planId) qs.set("planId", params.planId);
543
+ if (params.chargeId) qs.set("chargeId", params.chargeId);
544
+ if (params.status) {
545
+ const statuses = Array.isArray(params.status) ? params.status : [params.status];
546
+ for (const s of statuses) qs.append("status", s);
547
+ }
548
+ const query = qs.toString();
549
+ const url = `/api/v1/refund-requests${query ? `?${query}` : ""}`;
550
+ return this.http.call(
551
+ (signal) => this.http.client.GET(url, { signal }).then(
552
+ (r) => r
553
+ )
554
+ );
555
+ }
556
+ /**
557
+ * Retrieve one refund request.
558
+ *
559
+ * @example
560
+ * const request = await garu.refundRequests.get(uuid);
561
+ * request.installmentPlanId ?? request.chargeId; // exactly one is set
562
+ */
563
+ async get(uuid) {
564
+ return this.http.call(
565
+ (signal) => this.http.client.GET(`/api/v1/refund-requests/${uuid}`, { signal }).then(
566
+ (r) => r
567
+ )
568
+ );
569
+ }
570
+ /**
571
+ * Record that you returned the money. Call this AFTER transferring it.
572
+ *
573
+ * Confirming closes a carnê as refunded, stops remaining parcelas, cancels
574
+ * open slips at the provider and claws back the affiliate and co-producer
575
+ * commissions on the parcelas that cleared. For a Pix or boleto charge it
576
+ * marks the charge reversed and fires `transaction.refunded`. Idempotent:
577
+ * confirming twice does not claw back twice.
578
+ *
579
+ * @example
580
+ * // 1. You send the money to the buyer, out of band.
581
+ * // 2. Then tell Garu it happened.
582
+ * await garu.refundRequests.confirm(uuid, {
583
+ * note: 'Pix devolvido em 14/08, e2e E12345678'
584
+ * });
585
+ */
586
+ async confirm(uuid, params = {}) {
587
+ return this.http.call(
588
+ (signal) => this.http.client.POST(`/api/v1/refund-requests/${uuid}/confirm`, {
589
+ body: params,
590
+ signal
591
+ }).then((r) => r)
592
+ );
593
+ }
594
+ /**
595
+ * Decline the request. The carnê is untouched and keeps running.
596
+ * Idempotent.
597
+ *
598
+ * @example
599
+ * await garu.refundRequests.reject(uuid, {
600
+ * note: 'Produto entregue e retirado na loja em 02/08'
601
+ * });
602
+ */
603
+ async reject(uuid, params = {}) {
604
+ return this.http.call(
605
+ (signal) => this.http.client.POST(`/api/v1/refund-requests/${uuid}/reject`, {
606
+ body: params,
607
+ signal
608
+ }).then((r) => r)
609
+ );
610
+ }
611
+ };
612
+
320
613
  // src/resources/customers.ts
321
614
  var Customers = class {
322
615
  constructor(http) {
@@ -334,10 +627,11 @@ var Customers = class {
334
627
  * phone: '11987654321',
335
628
  * personType: 'fisica'
336
629
  * });
630
+ * customer.uuid;
337
631
  */
338
632
  async create(params) {
339
633
  return this.http.call(
340
- (signal) => this.http.client.POST("/api/customers", {
634
+ (signal) => this.http.client.POST("/api/v1/customers", {
341
635
  body: params,
342
636
  signal
343
637
  }).then((r) => r)
@@ -347,7 +641,11 @@ var Customers = class {
347
641
  * List customers for the authenticated seller, with pagination and search.
348
642
  *
349
643
  * @example
350
- * const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });
644
+ * const { data, totalCount } = await garu.customers.list({ search: 'maria', limit: 10 });
645
+ *
646
+ * @example
647
+ * // Customers with at least one overdue scheduled charge (carnê included).
648
+ * const atRisk = await garu.customers.list({ status: 'overdue' });
351
649
  */
352
650
  async list(params = {}) {
353
651
  const query = {};
@@ -356,7 +654,7 @@ var Customers = class {
356
654
  if (params.search) query.search = params.search;
357
655
  if (params.status) query.status = params.status;
358
656
  const qs = new URLSearchParams(query).toString();
359
- const url = `/api/customers${qs ? `?${qs}` : ""}`;
657
+ const url = `/api/v1/customers${qs ? `?${qs}` : ""}`;
360
658
  return this.http.call(
361
659
  (signal) => this.http.client.GET(url, { signal }).then(
362
660
  (r) => r
@@ -364,27 +662,28 @@ var Customers = class {
364
662
  );
365
663
  }
366
664
  /**
367
- * Fetch a single customer by numeric ID.
665
+ * Fetch a single customer by uuid.
368
666
  *
369
667
  * @example
370
- * const customer = await garu.customers.get(42);
668
+ * const customer = await garu.customers.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
371
669
  */
372
- async get(id) {
670
+ async get(uuid) {
373
671
  return this.http.call(
374
- (signal) => this.http.client.GET(`/api/customers/${id}`, { signal }).then(
672
+ (signal) => this.http.client.GET(`/api/v1/customers/${uuid}`, { signal }).then(
375
673
  (r) => r
376
674
  )
377
675
  );
378
676
  }
379
677
  /**
380
- * Update a customer's profile for the current seller.
678
+ * Update a customer's profile for the current seller. Partial — only the
679
+ * fields you pass change.
381
680
  *
382
681
  * @example
383
- * const updated = await garu.customers.update(42, { name: 'Maria Santos' });
682
+ * const updated = await garu.customers.update('a1b2c3d4-...', { name: 'Maria Santos' });
384
683
  */
385
- async update(id, params) {
684
+ async update(uuid, params) {
386
685
  return this.http.call(
387
- (signal) => this.http.client.PUT(`/api/customers/${id}`, {
686
+ (signal) => this.http.client.PATCH(`/api/v1/customers/${uuid}`, {
388
687
  body: params,
389
688
  signal
390
689
  }).then((r) => r)
@@ -399,30 +698,31 @@ var Customers = class {
399
698
  *
400
699
  * @example
401
700
  * // Set
402
- * await garu.customers.setBillingEmailOverride(42, {
701
+ * await garu.customers.setBillingEmailOverride('a1b2c3d4-...', {
403
702
  * billingEmailOverride: 'cobrancas@empresa.com.br'
404
703
  * });
405
704
  *
406
705
  * // Clear and fall back to the last-used email
407
- * await garu.customers.setBillingEmailOverride(42, { billingEmailOverride: null });
706
+ * await garu.customers.setBillingEmailOverride('a1b2c3d4-...', { billingEmailOverride: null });
408
707
  */
409
- async setBillingEmailOverride(id, params) {
708
+ async setBillingEmailOverride(uuid, params) {
410
709
  return this.http.call(
411
- (signal) => this.http.client.PATCH(`/api/customers/${id}/billing-email-override`, {
710
+ (signal) => this.http.client.PATCH(`/api/v1/customers/${uuid}/billing-email-override`, {
412
711
  body: params,
413
712
  signal
414
713
  }).then((r) => r)
415
714
  );
416
715
  }
417
716
  /**
418
- * Remove a customer from the current seller.
717
+ * Remove a customer from the current seller (unlinks your profile — the
718
+ * global customer and other sellers' profiles are untouched).
419
719
  *
420
720
  * @example
421
- * await garu.customers.delete(42);
721
+ * await garu.customers.delete('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
422
722
  */
423
- async delete(id) {
424
- await this.http.call(
425
- (signal) => this.http.client.DELETE(`/api/customers/${id}`, {
723
+ async delete(uuid) {
724
+ return this.http.call(
725
+ (signal) => this.http.client.DELETE(`/api/v1/customers/${uuid}`, {
426
726
  body: {},
427
727
  signal
428
728
  }).then((r) => r)
@@ -1160,6 +1460,10 @@ var DEFAULT_MAX_RETRIES = 2;
1160
1460
  var SDK_VERSION = "0.11.1";
1161
1461
  var Garu = class {
1162
1462
  charges;
1463
+ /** Boleto parcelado (carnê): one product sold as N monthly bank slips. */
1464
+ installmentPlans;
1465
+ /** Refunds Garu has been asked to make and cannot make for you. */
1466
+ refundRequests;
1163
1467
  customers;
1164
1468
  meta;
1165
1469
  products;
@@ -1181,6 +1485,8 @@ var Garu = class {
1181
1485
  fetch: options.fetch
1182
1486
  });
1183
1487
  this.charges = new Charges(http);
1488
+ this.installmentPlans = new InstallmentPlans(http);
1489
+ this.refundRequests = new RefundRequests(http);
1184
1490
  this.customers = new Customers(http);
1185
1491
  this.meta = new Meta(http);
1186
1492
  this.products = new Products(http);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Official Node.js / TypeScript SDK for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",