@garuhq/node 0.4.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,41 @@
3
3
  All notable changes to `@garuhq/node` are documented in this file. Format:
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
5
5
 
6
+ ## [0.5.0] — 2026-05-01
7
+
8
+ ### Added
9
+
10
+ - `scheduledCharges` resource on the `Garu` client. Schedule a charge to
11
+ bill a customer on a future date; Garu drives the customer reminder
12
+ on the due date and dunning to the seller team after.
13
+ - `scheduledCharges.create({ customerId, amount, type, dueDate, methods, ... })`
14
+ — `POST /api/scheduled-charges`. PIX and Boleto are supported now;
15
+ `type` accepts only `one_time` in this version.
16
+ - `scheduledCharges.list({ status?, customerId?, type?, dueFrom?, dueTo?, search?, ... })`
17
+ — `GET /api/scheduled-charges`. `status` accepts a single value or
18
+ an array; arrays are sent as repeated query params.
19
+ - `scheduledCharges.get(id)` — `GET /api/scheduled-charges/{id}`.
20
+ Returns a bundle: `{ charge, events, transactions }`.
21
+ - `scheduledCharges.postpone(id, { newDueDate, reason? })` — allowed
22
+ from `scheduled` / `due_today` / `overdue` / `paused`. Clears any
23
+ pending dunning so the new dueDate triggers a fresh reminder.
24
+ - `scheduledCharges.pause(id, { reason? })` — allowed from
25
+ `scheduled` / `due_today` / `overdue`.
26
+ - `scheduledCharges.resume(id)` — only valid from `paused`.
27
+ - `scheduledCharges.markPaid(id, { paymentDate, externalReference? })`
28
+ — record an off-Garu payment (transfer, cash). Allowed from
29
+ `due_today` / `overdue`.
30
+ - `customers.list({ status: 'overdue' })` — new filter that returns
31
+ customers with at least one overdue scheduled charge.
32
+ - Types exported from the package root: `CreateScheduledChargeParams`,
33
+ `ListScheduledChargesParams`, `MarkPaidScheduledChargeParams`,
34
+ `PauseScheduledChargeParams`, `PostponeScheduledChargeParams`,
35
+ `ScheduledChargeActor`, `ScheduledChargeDetail`,
36
+ `ScheduledChargeEvent`, `ScheduledChargeEventType`,
37
+ `ScheduledChargeLinkedTransaction`, `ScheduledChargeList`,
38
+ `ScheduledChargeRecord`, `ScheduledChargeStatus`,
39
+ `ScheduledChargeType`, `ScheduledPaymentMethod`.
40
+
6
41
  ## [0.3.0] — 2026-04-28
7
42
 
8
43
  ### Added
package/dist/index.cjs CHANGED
@@ -367,6 +367,7 @@ var Customers = class {
367
367
  if (params.page !== void 0) query.page = String(params.page);
368
368
  if (params.limit !== void 0) query.limit = String(params.limit);
369
369
  if (params.search) query.search = params.search;
370
+ if (params.status) query.status = params.status;
370
371
  const qs = new URLSearchParams(query).toString();
371
372
  const url = `/api/customers${qs ? `?${qs}` : ""}`;
372
373
  return this.http.call(
@@ -503,6 +504,236 @@ var Products = class {
503
504
  );
504
505
  }
505
506
  };
507
+
508
+ // src/resources/scheduled-charges.ts
509
+ var ScheduledCharges = class {
510
+ constructor(http) {
511
+ this.http = http;
512
+ }
513
+ http;
514
+ /**
515
+ * Create a new scheduled charge. Auto-attaches `X-Idempotency-Key`
516
+ * (UUIDv4 if you don't pass `idempotencyKey`) so retries on transient
517
+ * network failures don't silently double-create.
518
+ *
519
+ * @example
520
+ * const charge = await garu.scheduledCharges.create({
521
+ * customerId: 42,
522
+ * amount: 297.50,
523
+ * type: 'one_time',
524
+ * dueDate: '2026-06-15',
525
+ * methods: ['pix', 'boleto'],
526
+ * description: 'Mensalidade Junho'
527
+ * });
528
+ */
529
+ async create(params) {
530
+ const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
531
+ const { idempotencyKey: _omit, ...body } = params;
532
+ return this.http.call(
533
+ (signal) => this.http.client.POST("/api/scheduled-charges", {
534
+ body,
535
+ headers: { "X-Idempotency-Key": idempotencyKey },
536
+ signal
537
+ }).then((r) => r)
538
+ );
539
+ }
540
+ /**
541
+ * List scheduled charges for the authenticated seller, with pagination
542
+ * and filters. Repeat the `status` array to filter on multiple values.
543
+ *
544
+ * @example
545
+ * const overdue = await garu.scheduledCharges.list({ status: 'overdue', limit: 50 });
546
+ *
547
+ * @example
548
+ * const upcoming = await garu.scheduledCharges.list({
549
+ * status: ['scheduled', 'due_today'],
550
+ * dueFrom: '2026-06-01',
551
+ * dueTo: '2026-06-30'
552
+ * });
553
+ */
554
+ async list(params = {}) {
555
+ const qs = new URLSearchParams();
556
+ if (params.page !== void 0) qs.set("page", String(params.page));
557
+ if (params.limit !== void 0) qs.set("limit", String(params.limit));
558
+ if (params.customerId !== void 0) qs.set("customerId", String(params.customerId));
559
+ if (params.type) qs.set("type", params.type);
560
+ if (params.dueFrom) qs.set("dueFrom", params.dueFrom);
561
+ if (params.dueTo) qs.set("dueTo", params.dueTo);
562
+ if (params.search) qs.set("search", params.search);
563
+ if (params.status) {
564
+ const statuses = Array.isArray(params.status) ? params.status : [params.status];
565
+ for (const s of statuses) qs.append("status", s);
566
+ }
567
+ const query = qs.toString();
568
+ const url = `/api/scheduled-charges${query ? `?${query}` : ""}`;
569
+ return this.http.call(
570
+ (signal) => this.http.client.GET(url, { signal }).then(
571
+ (r) => r
572
+ )
573
+ );
574
+ }
575
+ /**
576
+ * Fetch a single scheduled charge by ID, bundled with its event timeline
577
+ * and any linked Garu transactions.
578
+ *
579
+ * @example
580
+ * const { charge, events, transactions } = await garu.scheduledCharges.get('sch_abc123');
581
+ * // charge.status, events[].eventType, transactions[].status
582
+ */
583
+ async get(id) {
584
+ return this.http.call(
585
+ (signal) => this.http.client.GET(`/api/scheduled-charges/${id}`, { signal }).then(
586
+ (r) => r
587
+ )
588
+ );
589
+ }
590
+ /**
591
+ * Postpone a scheduled charge to a new due date. Allowed from
592
+ * `scheduled` / `due_today` / `overdue` / `paused`. Clears any pending
593
+ * dunning so the new dueDate triggers a fresh customer reminder.
594
+ *
595
+ * @example
596
+ * await garu.scheduledCharges.postpone('sch_abc123', {
597
+ * newDueDate: '2026-07-01',
598
+ * reason: 'cliente pediu mais prazo'
599
+ * });
600
+ */
601
+ async postpone(id, params) {
602
+ return this.http.call(
603
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/postpone`, {
604
+ body: params,
605
+ signal
606
+ }).then((r) => r)
607
+ );
608
+ }
609
+ /**
610
+ * Pause a scheduled charge. No reminders fire while paused. Resume
611
+ * returns it to `scheduled`. Allowed from
612
+ * `scheduled` / `due_today` / `overdue`.
613
+ *
614
+ * @example
615
+ * await garu.scheduledCharges.pause('sch_abc123', { reason: 'em negociação' });
616
+ */
617
+ async pause(id, params = {}) {
618
+ return this.http.call(
619
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/pause`, {
620
+ body: params,
621
+ signal
622
+ }).then((r) => r)
623
+ );
624
+ }
625
+ /**
626
+ * Resume a paused scheduled charge. Only valid from `paused`.
627
+ *
628
+ * @example
629
+ * await garu.scheduledCharges.resume('sch_abc123');
630
+ */
631
+ async resume(id) {
632
+ return this.http.call(
633
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/resume`, {
634
+ signal
635
+ }).then((r) => r)
636
+ );
637
+ }
638
+ /**
639
+ * Manually mark a scheduled charge as paid, e.g. when the customer paid
640
+ * outside Garu (bank transfer, cash).
641
+ *
642
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
643
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
644
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
645
+ *
646
+ * @example
647
+ * // One-time
648
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
649
+ * paymentDate: '2026-06-20',
650
+ * externalReference: 'TED 4472881'
651
+ * });
652
+ *
653
+ * @example
654
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
655
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
656
+ * cycleNumber: 3,
657
+ * paymentDate: '2026-06-20',
658
+ * externalReference: 'TED 4472881'
659
+ * });
660
+ */
661
+ async markPaid(id, params) {
662
+ return this.http.call(
663
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/mark-paid`, {
664
+ body: params,
665
+ signal
666
+ }).then((r) => r)
667
+ );
668
+ }
669
+ /**
670
+ * Stop future cycles for a recurring series. The currently in-flight
671
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
672
+ * only after that resolves does the series flip to `recurrence_canceled`.
673
+ * Recurring-only.
674
+ *
675
+ * @example
676
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
677
+ * reason: 'cliente cancelou plano'
678
+ * });
679
+ */
680
+ async cancelRecurrence(id, params = {}) {
681
+ return this.http.call(
682
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
683
+ body: params,
684
+ signal
685
+ }).then((r) => r)
686
+ );
687
+ }
688
+ /**
689
+ * Toggle Stripe-style soft cancel on a recurring series. With
690
+ * `enabled: true`, the cycle generator stops emitting new cycles after
691
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
692
+ * Reversible by passing `enabled: false`. Recurring-only.
693
+ *
694
+ * @example
695
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
696
+ */
697
+ async setCancelAtPeriodEnd(id, params) {
698
+ return this.http.call(
699
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
700
+ body: params,
701
+ signal
702
+ }).then((r) => r)
703
+ );
704
+ }
705
+ /**
706
+ * Swap the saved card on a recurring series. The new PaymentMethod must
707
+ * belong to the same customerId. Future cycles silent-charge the new
708
+ * card; the in-flight cycle is not retroactively rebound.
709
+ *
710
+ * @example
711
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
712
+ */
713
+ async changePaymentMethod(id, params) {
714
+ return this.http.call(
715
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
716
+ body: params,
717
+ signal
718
+ }).then((r) => r)
719
+ );
720
+ }
721
+ /**
722
+ * Clear the saved card on a recurring series. Future cycles fall back
723
+ * to the email-with-link flow so the customer can re-enter card details
724
+ * or pay via PIX/Boleto.
725
+ *
726
+ * @example
727
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
728
+ */
729
+ async clearPaymentMethod(id) {
730
+ return this.http.call(
731
+ (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
732
+ signal
733
+ }).then((r) => r)
734
+ );
735
+ }
736
+ };
506
737
  var webhooks = {
507
738
  verify(params) {
508
739
  const { signature, secret, payload } = params;
@@ -568,6 +799,7 @@ var Garu = class {
568
799
  customers;
569
800
  meta;
570
801
  products;
802
+ scheduledCharges;
571
803
  /**
572
804
  * Webhook helpers. Available both as an instance member and as a static —
573
805
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -587,6 +819,7 @@ var Garu = class {
587
819
  this.customers = new Customers(http);
588
820
  this.meta = new Meta(http);
589
821
  this.products = new Products(http);
822
+ this.scheduledCharges = new ScheduledCharges(http);
590
823
  }
591
824
  };
592
825
 
package/dist/index.d.cts CHANGED
@@ -272,6 +272,162 @@ interface ListCustomersParams {
272
272
  page?: number;
273
273
  limit?: number;
274
274
  search?: string;
275
+ /** Filter by aggregated status. `overdue` returns customers with at least one overdue scheduled charge. */
276
+ status?: 'overdue';
277
+ }
278
+ type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
+ type ScheduledChargeType = 'one_time' | 'recurring';
280
+ type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card';
281
+ type RecurrenceInterval = 'weekly' | 'biweekly' | 'monthly' | 'bimonthly' | 'quarterly' | 'biannual' | 'yearly';
282
+ interface RecurrenceConfig {
283
+ interval: RecurrenceInterval;
284
+ /** Multiplier for the interval (default 1). */
285
+ intervalCount?: number;
286
+ /** Stop after N successful cycles. Mutually exclusive with `endsOn`. */
287
+ endsAfter?: number;
288
+ /** Stop after this calendar date (YYYY-MM-DD). Mutually exclusive with `endsAfter`. */
289
+ endsOn?: string;
290
+ }
291
+ type ScheduledChargeEventType = 'created' | 'postponed' | 'paused' | 'resumed' | 'recurrence_canceled' | 'manually_marked_paid' | 'paid' | 'overdue_reminder_sent' | 'd_day_reminder_sent';
292
+ type ScheduledChargeActor = {
293
+ type: 'user';
294
+ id: number;
295
+ } | {
296
+ type: 'api_key';
297
+ id: number;
298
+ } | {
299
+ type: 'system';
300
+ };
301
+ interface ScheduledChargeRecord {
302
+ id: string;
303
+ sellerId: number;
304
+ customerId: number;
305
+ productId: number | null;
306
+ /** Decimal BRL (e.g. `297.50`), never centavos. */
307
+ amount: number;
308
+ description: string | null;
309
+ type: ScheduledChargeType;
310
+ /** YYYY-MM-DD in São Paulo time. */
311
+ dueDate: string;
312
+ methods: ScheduledPaymentMethod[];
313
+ status: ScheduledChargeStatus;
314
+ externalReference: string | null;
315
+ metadata: Record<string, unknown> | null;
316
+ createdAt: string;
317
+ updatedAt: string;
318
+ /** Eager-loaded customer (id/name/email/document only). */
319
+ customer?: {
320
+ id: number;
321
+ name: string;
322
+ email: string;
323
+ document: string;
324
+ } | null;
325
+ /** Eager-loaded product (id/uuid/name only). */
326
+ product?: {
327
+ id: number;
328
+ uuid: string;
329
+ name: string;
330
+ } | null;
331
+ [key: string]: unknown;
332
+ }
333
+ interface ScheduledChargeEvent {
334
+ id: number;
335
+ scheduledChargeId: string;
336
+ eventType: ScheduledChargeEventType;
337
+ actor: ScheduledChargeActor;
338
+ payload: Record<string, unknown> | null;
339
+ createdAt: string;
340
+ }
341
+ interface ScheduledChargeLinkedTransaction {
342
+ id: number;
343
+ /** Centavos (BRL × 100), matching `garu.charges.*` value semantics. */
344
+ value: number;
345
+ paymentMethod: string;
346
+ status: string;
347
+ date: string;
348
+ refundedAt: string | null;
349
+ [key: string]: unknown;
350
+ }
351
+ interface ScheduledChargeDetail {
352
+ charge: ScheduledChargeRecord;
353
+ events: ScheduledChargeEvent[];
354
+ transactions: ScheduledChargeLinkedTransaction[];
355
+ }
356
+ type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
357
+ interface CreateScheduledChargeParams {
358
+ customerId: number;
359
+ /**
360
+ * Required when `methods` includes `card` — Celcoin transactions are
361
+ * scoped per product. Optional otherwise.
362
+ */
363
+ productId?: number;
364
+ /** Decimal BRL (e.g. `297.50`). */
365
+ amount: number;
366
+ description?: string;
367
+ /** Schedule type. `recurring` requires a `recurrence` block. */
368
+ type: ScheduledChargeType;
369
+ /** YYYY-MM-DD in São Paulo time. Must be today or future. */
370
+ dueDate: string;
371
+ /** `card` is recurring-only and requires `productId`. */
372
+ methods: ScheduledPaymentMethod[];
373
+ /** Cadence for `type='recurring'`. Must be omitted when `type='one_time'`. */
374
+ recurrence?: RecurrenceConfig;
375
+ /**
376
+ * Free-trial duration in days (1..365). Recurring-only. When set, cycle 1
377
+ * is rebased to `today + trialDays` and `customer.trial_started` fires
378
+ * immediately.
379
+ */
380
+ trialDays?: number;
381
+ externalReference?: string;
382
+ metadata?: Record<string, unknown>;
383
+ /**
384
+ * Optional idempotency key for safe retries. The SDK auto-generates a
385
+ * UUIDv4 when omitted and forwards it as `X-Idempotency-Key`.
386
+ */
387
+ idempotencyKey?: string;
388
+ }
389
+ interface ListScheduledChargesParams {
390
+ page?: number;
391
+ limit?: number;
392
+ customerId?: number;
393
+ status?: ScheduledChargeStatus | ScheduledChargeStatus[];
394
+ type?: ScheduledChargeType;
395
+ /** YYYY-MM-DD lower bound for `dueDate`. */
396
+ dueFrom?: string;
397
+ /** YYYY-MM-DD upper bound for `dueDate`. */
398
+ dueTo?: string;
399
+ /** Free-text match against customer name / email / document. */
400
+ search?: string;
401
+ }
402
+ interface PostponeScheduledChargeParams {
403
+ /** YYYY-MM-DD in São Paulo time. Must be today or future. */
404
+ newDueDate: string;
405
+ reason?: string;
406
+ }
407
+ interface PauseScheduledChargeParams {
408
+ reason?: string;
409
+ }
410
+ interface MarkPaidScheduledChargeParams {
411
+ /** YYYY-MM-DD in São Paulo time. Must be today or past. */
412
+ paymentDate: string;
413
+ /** Bank reference, internal ID, or any stable string for reconciliation. */
414
+ externalReference?: string;
415
+ /**
416
+ * Cycle number to mark paid. REQUIRED for recurring schedules. Omitted
417
+ * for one-time charges.
418
+ */
419
+ cycleNumber?: number;
420
+ }
421
+ interface CancelRecurrenceScheduledChargeParams {
422
+ reason?: string;
423
+ }
424
+ interface CancelAtPeriodEndScheduledChargeParams {
425
+ /** `true` enables Stripe-style soft cancel; `false` clears the flag. */
426
+ enabled: boolean;
427
+ }
428
+ interface ChangePaymentMethodScheduledChargeParams {
429
+ /** PaymentMethod id to bind. Must belong to the same customerId. */
430
+ paymentMethodId: number;
275
431
  }
276
432
  interface Product {
277
433
  id: number;
@@ -526,6 +682,157 @@ declare class Products {
526
682
  get(uuid: string): Promise<Product>;
527
683
  }
528
684
 
685
+ /**
686
+ * Scheduled charges — bill a customer on a future date.
687
+ *
688
+ * The seller registers a customer (see `garu.customers.create`), then
689
+ * schedules one or more charges (PIX, Boleto, or Card). Garu drives the
690
+ * rest: pre-charge customer email on the due date, dunning to the seller
691
+ * team after the due date, and a state machine for
692
+ * postpone/pause/resume/mark-paid actions.
693
+ *
694
+ * Recurring schedules (`type: 'recurring'`) silent-charge the saved card
695
+ * on every cycle past the first. Optional trial periods, cancel-recurrence,
696
+ * cancel-at-period-end, and payment-method swap actions cover the SaaS
697
+ * lifecycle.
698
+ */
699
+ declare class ScheduledCharges {
700
+ private readonly http;
701
+ constructor(http: HttpClient);
702
+ /**
703
+ * Create a new scheduled charge. Auto-attaches `X-Idempotency-Key`
704
+ * (UUIDv4 if you don't pass `idempotencyKey`) so retries on transient
705
+ * network failures don't silently double-create.
706
+ *
707
+ * @example
708
+ * const charge = await garu.scheduledCharges.create({
709
+ * customerId: 42,
710
+ * amount: 297.50,
711
+ * type: 'one_time',
712
+ * dueDate: '2026-06-15',
713
+ * methods: ['pix', 'boleto'],
714
+ * description: 'Mensalidade Junho'
715
+ * });
716
+ */
717
+ create(params: CreateScheduledChargeParams): Promise<ScheduledChargeRecord>;
718
+ /**
719
+ * List scheduled charges for the authenticated seller, with pagination
720
+ * and filters. Repeat the `status` array to filter on multiple values.
721
+ *
722
+ * @example
723
+ * const overdue = await garu.scheduledCharges.list({ status: 'overdue', limit: 50 });
724
+ *
725
+ * @example
726
+ * const upcoming = await garu.scheduledCharges.list({
727
+ * status: ['scheduled', 'due_today'],
728
+ * dueFrom: '2026-06-01',
729
+ * dueTo: '2026-06-30'
730
+ * });
731
+ */
732
+ list(params?: ListScheduledChargesParams): Promise<ScheduledChargeList>;
733
+ /**
734
+ * Fetch a single scheduled charge by ID, bundled with its event timeline
735
+ * and any linked Garu transactions.
736
+ *
737
+ * @example
738
+ * const { charge, events, transactions } = await garu.scheduledCharges.get('sch_abc123');
739
+ * // charge.status, events[].eventType, transactions[].status
740
+ */
741
+ get(id: string): Promise<ScheduledChargeDetail>;
742
+ /**
743
+ * Postpone a scheduled charge to a new due date. Allowed from
744
+ * `scheduled` / `due_today` / `overdue` / `paused`. Clears any pending
745
+ * dunning so the new dueDate triggers a fresh customer reminder.
746
+ *
747
+ * @example
748
+ * await garu.scheduledCharges.postpone('sch_abc123', {
749
+ * newDueDate: '2026-07-01',
750
+ * reason: 'cliente pediu mais prazo'
751
+ * });
752
+ */
753
+ postpone(id: string, params: PostponeScheduledChargeParams): Promise<ScheduledChargeRecord>;
754
+ /**
755
+ * Pause a scheduled charge. No reminders fire while paused. Resume
756
+ * returns it to `scheduled`. Allowed from
757
+ * `scheduled` / `due_today` / `overdue`.
758
+ *
759
+ * @example
760
+ * await garu.scheduledCharges.pause('sch_abc123', { reason: 'em negociação' });
761
+ */
762
+ pause(id: string, params?: PauseScheduledChargeParams): Promise<ScheduledChargeRecord>;
763
+ /**
764
+ * Resume a paused scheduled charge. Only valid from `paused`.
765
+ *
766
+ * @example
767
+ * await garu.scheduledCharges.resume('sch_abc123');
768
+ */
769
+ resume(id: string): Promise<ScheduledChargeRecord>;
770
+ /**
771
+ * Manually mark a scheduled charge as paid, e.g. when the customer paid
772
+ * outside Garu (bank transfer, cash).
773
+ *
774
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
775
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
776
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
777
+ *
778
+ * @example
779
+ * // One-time
780
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
781
+ * paymentDate: '2026-06-20',
782
+ * externalReference: 'TED 4472881'
783
+ * });
784
+ *
785
+ * @example
786
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
787
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
788
+ * cycleNumber: 3,
789
+ * paymentDate: '2026-06-20',
790
+ * externalReference: 'TED 4472881'
791
+ * });
792
+ */
793
+ markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
794
+ /**
795
+ * Stop future cycles for a recurring series. The currently in-flight
796
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
797
+ * only after that resolves does the series flip to `recurrence_canceled`.
798
+ * Recurring-only.
799
+ *
800
+ * @example
801
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
802
+ * reason: 'cliente cancelou plano'
803
+ * });
804
+ */
805
+ cancelRecurrence(id: string, params?: CancelRecurrenceScheduledChargeParams): Promise<ScheduledChargeRecord>;
806
+ /**
807
+ * Toggle Stripe-style soft cancel on a recurring series. With
808
+ * `enabled: true`, the cycle generator stops emitting new cycles after
809
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
810
+ * Reversible by passing `enabled: false`. Recurring-only.
811
+ *
812
+ * @example
813
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
814
+ */
815
+ setCancelAtPeriodEnd(id: string, params: CancelAtPeriodEndScheduledChargeParams): Promise<ScheduledChargeRecord>;
816
+ /**
817
+ * Swap the saved card on a recurring series. The new PaymentMethod must
818
+ * belong to the same customerId. Future cycles silent-charge the new
819
+ * card; the in-flight cycle is not retroactively rebound.
820
+ *
821
+ * @example
822
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
823
+ */
824
+ changePaymentMethod(id: string, params: ChangePaymentMethodScheduledChargeParams): Promise<ScheduledChargeRecord>;
825
+ /**
826
+ * Clear the saved card on a recurring series. Future cycles fall back
827
+ * to the email-with-link flow so the customer can re-enter card details
828
+ * or pay via PIX/Boleto.
829
+ *
830
+ * @example
831
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
832
+ */
833
+ clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
834
+ }
835
+
529
836
  interface GaruOptions {
530
837
  /**
531
838
  * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.
@@ -565,6 +872,7 @@ declare class Garu {
565
872
  readonly customers: Customers;
566
873
  readonly meta: Meta;
567
874
  readonly products: Products;
875
+ readonly scheduledCharges: ScheduledCharges;
568
876
  /**
569
877
  * Webhook helpers. Available both as an instance member and as a static —
570
878
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -623,4 +931,4 @@ declare class GaruServerError extends GaruAPIError {
623
931
  constructor(message: string, status: number, requestId: string | null, body: unknown);
624
932
  }
625
933
 
626
- export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type Product, type ProductList, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
934
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.d.ts CHANGED
@@ -272,6 +272,162 @@ interface ListCustomersParams {
272
272
  page?: number;
273
273
  limit?: number;
274
274
  search?: string;
275
+ /** Filter by aggregated status. `overdue` returns customers with at least one overdue scheduled charge. */
276
+ status?: 'overdue';
277
+ }
278
+ type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
+ type ScheduledChargeType = 'one_time' | 'recurring';
280
+ type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card';
281
+ type RecurrenceInterval = 'weekly' | 'biweekly' | 'monthly' | 'bimonthly' | 'quarterly' | 'biannual' | 'yearly';
282
+ interface RecurrenceConfig {
283
+ interval: RecurrenceInterval;
284
+ /** Multiplier for the interval (default 1). */
285
+ intervalCount?: number;
286
+ /** Stop after N successful cycles. Mutually exclusive with `endsOn`. */
287
+ endsAfter?: number;
288
+ /** Stop after this calendar date (YYYY-MM-DD). Mutually exclusive with `endsAfter`. */
289
+ endsOn?: string;
290
+ }
291
+ type ScheduledChargeEventType = 'created' | 'postponed' | 'paused' | 'resumed' | 'recurrence_canceled' | 'manually_marked_paid' | 'paid' | 'overdue_reminder_sent' | 'd_day_reminder_sent';
292
+ type ScheduledChargeActor = {
293
+ type: 'user';
294
+ id: number;
295
+ } | {
296
+ type: 'api_key';
297
+ id: number;
298
+ } | {
299
+ type: 'system';
300
+ };
301
+ interface ScheduledChargeRecord {
302
+ id: string;
303
+ sellerId: number;
304
+ customerId: number;
305
+ productId: number | null;
306
+ /** Decimal BRL (e.g. `297.50`), never centavos. */
307
+ amount: number;
308
+ description: string | null;
309
+ type: ScheduledChargeType;
310
+ /** YYYY-MM-DD in São Paulo time. */
311
+ dueDate: string;
312
+ methods: ScheduledPaymentMethod[];
313
+ status: ScheduledChargeStatus;
314
+ externalReference: string | null;
315
+ metadata: Record<string, unknown> | null;
316
+ createdAt: string;
317
+ updatedAt: string;
318
+ /** Eager-loaded customer (id/name/email/document only). */
319
+ customer?: {
320
+ id: number;
321
+ name: string;
322
+ email: string;
323
+ document: string;
324
+ } | null;
325
+ /** Eager-loaded product (id/uuid/name only). */
326
+ product?: {
327
+ id: number;
328
+ uuid: string;
329
+ name: string;
330
+ } | null;
331
+ [key: string]: unknown;
332
+ }
333
+ interface ScheduledChargeEvent {
334
+ id: number;
335
+ scheduledChargeId: string;
336
+ eventType: ScheduledChargeEventType;
337
+ actor: ScheduledChargeActor;
338
+ payload: Record<string, unknown> | null;
339
+ createdAt: string;
340
+ }
341
+ interface ScheduledChargeLinkedTransaction {
342
+ id: number;
343
+ /** Centavos (BRL × 100), matching `garu.charges.*` value semantics. */
344
+ value: number;
345
+ paymentMethod: string;
346
+ status: string;
347
+ date: string;
348
+ refundedAt: string | null;
349
+ [key: string]: unknown;
350
+ }
351
+ interface ScheduledChargeDetail {
352
+ charge: ScheduledChargeRecord;
353
+ events: ScheduledChargeEvent[];
354
+ transactions: ScheduledChargeLinkedTransaction[];
355
+ }
356
+ type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
357
+ interface CreateScheduledChargeParams {
358
+ customerId: number;
359
+ /**
360
+ * Required when `methods` includes `card` — Celcoin transactions are
361
+ * scoped per product. Optional otherwise.
362
+ */
363
+ productId?: number;
364
+ /** Decimal BRL (e.g. `297.50`). */
365
+ amount: number;
366
+ description?: string;
367
+ /** Schedule type. `recurring` requires a `recurrence` block. */
368
+ type: ScheduledChargeType;
369
+ /** YYYY-MM-DD in São Paulo time. Must be today or future. */
370
+ dueDate: string;
371
+ /** `card` is recurring-only and requires `productId`. */
372
+ methods: ScheduledPaymentMethod[];
373
+ /** Cadence for `type='recurring'`. Must be omitted when `type='one_time'`. */
374
+ recurrence?: RecurrenceConfig;
375
+ /**
376
+ * Free-trial duration in days (1..365). Recurring-only. When set, cycle 1
377
+ * is rebased to `today + trialDays` and `customer.trial_started` fires
378
+ * immediately.
379
+ */
380
+ trialDays?: number;
381
+ externalReference?: string;
382
+ metadata?: Record<string, unknown>;
383
+ /**
384
+ * Optional idempotency key for safe retries. The SDK auto-generates a
385
+ * UUIDv4 when omitted and forwards it as `X-Idempotency-Key`.
386
+ */
387
+ idempotencyKey?: string;
388
+ }
389
+ interface ListScheduledChargesParams {
390
+ page?: number;
391
+ limit?: number;
392
+ customerId?: number;
393
+ status?: ScheduledChargeStatus | ScheduledChargeStatus[];
394
+ type?: ScheduledChargeType;
395
+ /** YYYY-MM-DD lower bound for `dueDate`. */
396
+ dueFrom?: string;
397
+ /** YYYY-MM-DD upper bound for `dueDate`. */
398
+ dueTo?: string;
399
+ /** Free-text match against customer name / email / document. */
400
+ search?: string;
401
+ }
402
+ interface PostponeScheduledChargeParams {
403
+ /** YYYY-MM-DD in São Paulo time. Must be today or future. */
404
+ newDueDate: string;
405
+ reason?: string;
406
+ }
407
+ interface PauseScheduledChargeParams {
408
+ reason?: string;
409
+ }
410
+ interface MarkPaidScheduledChargeParams {
411
+ /** YYYY-MM-DD in São Paulo time. Must be today or past. */
412
+ paymentDate: string;
413
+ /** Bank reference, internal ID, or any stable string for reconciliation. */
414
+ externalReference?: string;
415
+ /**
416
+ * Cycle number to mark paid. REQUIRED for recurring schedules. Omitted
417
+ * for one-time charges.
418
+ */
419
+ cycleNumber?: number;
420
+ }
421
+ interface CancelRecurrenceScheduledChargeParams {
422
+ reason?: string;
423
+ }
424
+ interface CancelAtPeriodEndScheduledChargeParams {
425
+ /** `true` enables Stripe-style soft cancel; `false` clears the flag. */
426
+ enabled: boolean;
427
+ }
428
+ interface ChangePaymentMethodScheduledChargeParams {
429
+ /** PaymentMethod id to bind. Must belong to the same customerId. */
430
+ paymentMethodId: number;
275
431
  }
276
432
  interface Product {
277
433
  id: number;
@@ -526,6 +682,157 @@ declare class Products {
526
682
  get(uuid: string): Promise<Product>;
527
683
  }
528
684
 
685
+ /**
686
+ * Scheduled charges — bill a customer on a future date.
687
+ *
688
+ * The seller registers a customer (see `garu.customers.create`), then
689
+ * schedules one or more charges (PIX, Boleto, or Card). Garu drives the
690
+ * rest: pre-charge customer email on the due date, dunning to the seller
691
+ * team after the due date, and a state machine for
692
+ * postpone/pause/resume/mark-paid actions.
693
+ *
694
+ * Recurring schedules (`type: 'recurring'`) silent-charge the saved card
695
+ * on every cycle past the first. Optional trial periods, cancel-recurrence,
696
+ * cancel-at-period-end, and payment-method swap actions cover the SaaS
697
+ * lifecycle.
698
+ */
699
+ declare class ScheduledCharges {
700
+ private readonly http;
701
+ constructor(http: HttpClient);
702
+ /**
703
+ * Create a new scheduled charge. Auto-attaches `X-Idempotency-Key`
704
+ * (UUIDv4 if you don't pass `idempotencyKey`) so retries on transient
705
+ * network failures don't silently double-create.
706
+ *
707
+ * @example
708
+ * const charge = await garu.scheduledCharges.create({
709
+ * customerId: 42,
710
+ * amount: 297.50,
711
+ * type: 'one_time',
712
+ * dueDate: '2026-06-15',
713
+ * methods: ['pix', 'boleto'],
714
+ * description: 'Mensalidade Junho'
715
+ * });
716
+ */
717
+ create(params: CreateScheduledChargeParams): Promise<ScheduledChargeRecord>;
718
+ /**
719
+ * List scheduled charges for the authenticated seller, with pagination
720
+ * and filters. Repeat the `status` array to filter on multiple values.
721
+ *
722
+ * @example
723
+ * const overdue = await garu.scheduledCharges.list({ status: 'overdue', limit: 50 });
724
+ *
725
+ * @example
726
+ * const upcoming = await garu.scheduledCharges.list({
727
+ * status: ['scheduled', 'due_today'],
728
+ * dueFrom: '2026-06-01',
729
+ * dueTo: '2026-06-30'
730
+ * });
731
+ */
732
+ list(params?: ListScheduledChargesParams): Promise<ScheduledChargeList>;
733
+ /**
734
+ * Fetch a single scheduled charge by ID, bundled with its event timeline
735
+ * and any linked Garu transactions.
736
+ *
737
+ * @example
738
+ * const { charge, events, transactions } = await garu.scheduledCharges.get('sch_abc123');
739
+ * // charge.status, events[].eventType, transactions[].status
740
+ */
741
+ get(id: string): Promise<ScheduledChargeDetail>;
742
+ /**
743
+ * Postpone a scheduled charge to a new due date. Allowed from
744
+ * `scheduled` / `due_today` / `overdue` / `paused`. Clears any pending
745
+ * dunning so the new dueDate triggers a fresh customer reminder.
746
+ *
747
+ * @example
748
+ * await garu.scheduledCharges.postpone('sch_abc123', {
749
+ * newDueDate: '2026-07-01',
750
+ * reason: 'cliente pediu mais prazo'
751
+ * });
752
+ */
753
+ postpone(id: string, params: PostponeScheduledChargeParams): Promise<ScheduledChargeRecord>;
754
+ /**
755
+ * Pause a scheduled charge. No reminders fire while paused. Resume
756
+ * returns it to `scheduled`. Allowed from
757
+ * `scheduled` / `due_today` / `overdue`.
758
+ *
759
+ * @example
760
+ * await garu.scheduledCharges.pause('sch_abc123', { reason: 'em negociação' });
761
+ */
762
+ pause(id: string, params?: PauseScheduledChargeParams): Promise<ScheduledChargeRecord>;
763
+ /**
764
+ * Resume a paused scheduled charge. Only valid from `paused`.
765
+ *
766
+ * @example
767
+ * await garu.scheduledCharges.resume('sch_abc123');
768
+ */
769
+ resume(id: string): Promise<ScheduledChargeRecord>;
770
+ /**
771
+ * Manually mark a scheduled charge as paid, e.g. when the customer paid
772
+ * outside Garu (bank transfer, cash).
773
+ *
774
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
775
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
776
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
777
+ *
778
+ * @example
779
+ * // One-time
780
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
781
+ * paymentDate: '2026-06-20',
782
+ * externalReference: 'TED 4472881'
783
+ * });
784
+ *
785
+ * @example
786
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
787
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
788
+ * cycleNumber: 3,
789
+ * paymentDate: '2026-06-20',
790
+ * externalReference: 'TED 4472881'
791
+ * });
792
+ */
793
+ markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
794
+ /**
795
+ * Stop future cycles for a recurring series. The currently in-flight
796
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
797
+ * only after that resolves does the series flip to `recurrence_canceled`.
798
+ * Recurring-only.
799
+ *
800
+ * @example
801
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
802
+ * reason: 'cliente cancelou plano'
803
+ * });
804
+ */
805
+ cancelRecurrence(id: string, params?: CancelRecurrenceScheduledChargeParams): Promise<ScheduledChargeRecord>;
806
+ /**
807
+ * Toggle Stripe-style soft cancel on a recurring series. With
808
+ * `enabled: true`, the cycle generator stops emitting new cycles after
809
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
810
+ * Reversible by passing `enabled: false`. Recurring-only.
811
+ *
812
+ * @example
813
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
814
+ */
815
+ setCancelAtPeriodEnd(id: string, params: CancelAtPeriodEndScheduledChargeParams): Promise<ScheduledChargeRecord>;
816
+ /**
817
+ * Swap the saved card on a recurring series. The new PaymentMethod must
818
+ * belong to the same customerId. Future cycles silent-charge the new
819
+ * card; the in-flight cycle is not retroactively rebound.
820
+ *
821
+ * @example
822
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
823
+ */
824
+ changePaymentMethod(id: string, params: ChangePaymentMethodScheduledChargeParams): Promise<ScheduledChargeRecord>;
825
+ /**
826
+ * Clear the saved card on a recurring series. Future cycles fall back
827
+ * to the email-with-link flow so the customer can re-enter card details
828
+ * or pay via PIX/Boleto.
829
+ *
830
+ * @example
831
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
832
+ */
833
+ clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
834
+ }
835
+
529
836
  interface GaruOptions {
530
837
  /**
531
838
  * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.
@@ -565,6 +872,7 @@ declare class Garu {
565
872
  readonly customers: Customers;
566
873
  readonly meta: Meta;
567
874
  readonly products: Products;
875
+ readonly scheduledCharges: ScheduledCharges;
568
876
  /**
569
877
  * Webhook helpers. Available both as an instance member and as a static —
570
878
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -623,4 +931,4 @@ declare class GaruServerError extends GaruAPIError {
623
931
  constructor(message: string, status: number, requestId: string | null, body: unknown);
624
932
  }
625
933
 
626
- export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type Product, type ProductList, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
934
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.js CHANGED
@@ -361,6 +361,7 @@ var Customers = class {
361
361
  if (params.page !== void 0) query.page = String(params.page);
362
362
  if (params.limit !== void 0) query.limit = String(params.limit);
363
363
  if (params.search) query.search = params.search;
364
+ if (params.status) query.status = params.status;
364
365
  const qs = new URLSearchParams(query).toString();
365
366
  const url = `/api/customers${qs ? `?${qs}` : ""}`;
366
367
  return this.http.call(
@@ -497,6 +498,236 @@ var Products = class {
497
498
  );
498
499
  }
499
500
  };
501
+
502
+ // src/resources/scheduled-charges.ts
503
+ var ScheduledCharges = class {
504
+ constructor(http) {
505
+ this.http = http;
506
+ }
507
+ http;
508
+ /**
509
+ * Create a new scheduled charge. Auto-attaches `X-Idempotency-Key`
510
+ * (UUIDv4 if you don't pass `idempotencyKey`) so retries on transient
511
+ * network failures don't silently double-create.
512
+ *
513
+ * @example
514
+ * const charge = await garu.scheduledCharges.create({
515
+ * customerId: 42,
516
+ * amount: 297.50,
517
+ * type: 'one_time',
518
+ * dueDate: '2026-06-15',
519
+ * methods: ['pix', 'boleto'],
520
+ * description: 'Mensalidade Junho'
521
+ * });
522
+ */
523
+ async create(params) {
524
+ const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
525
+ const { idempotencyKey: _omit, ...body } = params;
526
+ return this.http.call(
527
+ (signal) => this.http.client.POST("/api/scheduled-charges", {
528
+ body,
529
+ headers: { "X-Idempotency-Key": idempotencyKey },
530
+ signal
531
+ }).then((r) => r)
532
+ );
533
+ }
534
+ /**
535
+ * List scheduled charges for the authenticated seller, with pagination
536
+ * and filters. Repeat the `status` array to filter on multiple values.
537
+ *
538
+ * @example
539
+ * const overdue = await garu.scheduledCharges.list({ status: 'overdue', limit: 50 });
540
+ *
541
+ * @example
542
+ * const upcoming = await garu.scheduledCharges.list({
543
+ * status: ['scheduled', 'due_today'],
544
+ * dueFrom: '2026-06-01',
545
+ * dueTo: '2026-06-30'
546
+ * });
547
+ */
548
+ async list(params = {}) {
549
+ const qs = new URLSearchParams();
550
+ if (params.page !== void 0) qs.set("page", String(params.page));
551
+ if (params.limit !== void 0) qs.set("limit", String(params.limit));
552
+ if (params.customerId !== void 0) qs.set("customerId", String(params.customerId));
553
+ if (params.type) qs.set("type", params.type);
554
+ if (params.dueFrom) qs.set("dueFrom", params.dueFrom);
555
+ if (params.dueTo) qs.set("dueTo", params.dueTo);
556
+ if (params.search) qs.set("search", params.search);
557
+ if (params.status) {
558
+ const statuses = Array.isArray(params.status) ? params.status : [params.status];
559
+ for (const s of statuses) qs.append("status", s);
560
+ }
561
+ const query = qs.toString();
562
+ const url = `/api/scheduled-charges${query ? `?${query}` : ""}`;
563
+ return this.http.call(
564
+ (signal) => this.http.client.GET(url, { signal }).then(
565
+ (r) => r
566
+ )
567
+ );
568
+ }
569
+ /**
570
+ * Fetch a single scheduled charge by ID, bundled with its event timeline
571
+ * and any linked Garu transactions.
572
+ *
573
+ * @example
574
+ * const { charge, events, transactions } = await garu.scheduledCharges.get('sch_abc123');
575
+ * // charge.status, events[].eventType, transactions[].status
576
+ */
577
+ async get(id) {
578
+ return this.http.call(
579
+ (signal) => this.http.client.GET(`/api/scheduled-charges/${id}`, { signal }).then(
580
+ (r) => r
581
+ )
582
+ );
583
+ }
584
+ /**
585
+ * Postpone a scheduled charge to a new due date. Allowed from
586
+ * `scheduled` / `due_today` / `overdue` / `paused`. Clears any pending
587
+ * dunning so the new dueDate triggers a fresh customer reminder.
588
+ *
589
+ * @example
590
+ * await garu.scheduledCharges.postpone('sch_abc123', {
591
+ * newDueDate: '2026-07-01',
592
+ * reason: 'cliente pediu mais prazo'
593
+ * });
594
+ */
595
+ async postpone(id, params) {
596
+ return this.http.call(
597
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/postpone`, {
598
+ body: params,
599
+ signal
600
+ }).then((r) => r)
601
+ );
602
+ }
603
+ /**
604
+ * Pause a scheduled charge. No reminders fire while paused. Resume
605
+ * returns it to `scheduled`. Allowed from
606
+ * `scheduled` / `due_today` / `overdue`.
607
+ *
608
+ * @example
609
+ * await garu.scheduledCharges.pause('sch_abc123', { reason: 'em negociação' });
610
+ */
611
+ async pause(id, params = {}) {
612
+ return this.http.call(
613
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/pause`, {
614
+ body: params,
615
+ signal
616
+ }).then((r) => r)
617
+ );
618
+ }
619
+ /**
620
+ * Resume a paused scheduled charge. Only valid from `paused`.
621
+ *
622
+ * @example
623
+ * await garu.scheduledCharges.resume('sch_abc123');
624
+ */
625
+ async resume(id) {
626
+ return this.http.call(
627
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/resume`, {
628
+ signal
629
+ }).then((r) => r)
630
+ );
631
+ }
632
+ /**
633
+ * Manually mark a scheduled charge as paid, e.g. when the customer paid
634
+ * outside Garu (bank transfer, cash).
635
+ *
636
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
637
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
638
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
639
+ *
640
+ * @example
641
+ * // One-time
642
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
643
+ * paymentDate: '2026-06-20',
644
+ * externalReference: 'TED 4472881'
645
+ * });
646
+ *
647
+ * @example
648
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
649
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
650
+ * cycleNumber: 3,
651
+ * paymentDate: '2026-06-20',
652
+ * externalReference: 'TED 4472881'
653
+ * });
654
+ */
655
+ async markPaid(id, params) {
656
+ return this.http.call(
657
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/mark-paid`, {
658
+ body: params,
659
+ signal
660
+ }).then((r) => r)
661
+ );
662
+ }
663
+ /**
664
+ * Stop future cycles for a recurring series. The currently in-flight
665
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
666
+ * only after that resolves does the series flip to `recurrence_canceled`.
667
+ * Recurring-only.
668
+ *
669
+ * @example
670
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
671
+ * reason: 'cliente cancelou plano'
672
+ * });
673
+ */
674
+ async cancelRecurrence(id, params = {}) {
675
+ return this.http.call(
676
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
677
+ body: params,
678
+ signal
679
+ }).then((r) => r)
680
+ );
681
+ }
682
+ /**
683
+ * Toggle Stripe-style soft cancel on a recurring series. With
684
+ * `enabled: true`, the cycle generator stops emitting new cycles after
685
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
686
+ * Reversible by passing `enabled: false`. Recurring-only.
687
+ *
688
+ * @example
689
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
690
+ */
691
+ async setCancelAtPeriodEnd(id, params) {
692
+ return this.http.call(
693
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
694
+ body: params,
695
+ signal
696
+ }).then((r) => r)
697
+ );
698
+ }
699
+ /**
700
+ * Swap the saved card on a recurring series. The new PaymentMethod must
701
+ * belong to the same customerId. Future cycles silent-charge the new
702
+ * card; the in-flight cycle is not retroactively rebound.
703
+ *
704
+ * @example
705
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
706
+ */
707
+ async changePaymentMethod(id, params) {
708
+ return this.http.call(
709
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
710
+ body: params,
711
+ signal
712
+ }).then((r) => r)
713
+ );
714
+ }
715
+ /**
716
+ * Clear the saved card on a recurring series. Future cycles fall back
717
+ * to the email-with-link flow so the customer can re-enter card details
718
+ * or pay via PIX/Boleto.
719
+ *
720
+ * @example
721
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
722
+ */
723
+ async clearPaymentMethod(id) {
724
+ return this.http.call(
725
+ (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
726
+ signal
727
+ }).then((r) => r)
728
+ );
729
+ }
730
+ };
500
731
  var webhooks = {
501
732
  verify(params) {
502
733
  const { signature, secret, payload } = params;
@@ -562,6 +793,7 @@ var Garu = class {
562
793
  customers;
563
794
  meta;
564
795
  products;
796
+ scheduledCharges;
565
797
  /**
566
798
  * Webhook helpers. Available both as an instance member and as a static —
567
799
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -581,6 +813,7 @@ var Garu = class {
581
813
  this.customers = new Customers(http);
582
814
  this.meta = new Meta(http);
583
815
  this.products = new Products(http);
816
+ this.scheduledCharges = new ScheduledCharges(http);
584
817
  }
585
818
  };
586
819
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.4.0",
3
+ "version": "0.6.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",