@garuhq/node 0.5.0 → 0.7.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.cjs CHANGED
@@ -464,11 +464,80 @@ var Meta = class {
464
464
  };
465
465
 
466
466
  // src/resources/products.ts
467
+ var ProductPortalConfigResource = class {
468
+ constructor(http) {
469
+ this.http = http;
470
+ }
471
+ http;
472
+ /**
473
+ * Get the portal customization for a product. Returns `null` when no
474
+ * per-product config exists (the product falls back to seller-level
475
+ * portal config).
476
+ *
477
+ * @example
478
+ * const cfg = await garu.products.portalConfig.get(57);
479
+ */
480
+ async get(productId) {
481
+ return this.http.call(
482
+ (signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
483
+ signal
484
+ }).then((r) => r)
485
+ );
486
+ }
487
+ /**
488
+ * Create or merge the portal customization (idempotent upsert). Both
489
+ * `set` and `patch` have the same merge semantics — only fields present
490
+ * in the body are written, unspecified fields keep their persisted
491
+ * value. Use `clear` to reset everything.
492
+ *
493
+ * @example
494
+ * await garu.products.portalConfig.set(57, {
495
+ * businessName: 'Coach Maria — Corrida & Trilha',
496
+ * primaryColor: '#257264',
497
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
498
+ * });
499
+ */
500
+ async set(productId, params) {
501
+ return this.http.call(
502
+ (signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
503
+ body: params,
504
+ signal
505
+ }).then((r) => r)
506
+ );
507
+ }
508
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
509
+ async patch(productId, params) {
510
+ return this.http.call(
511
+ (signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
512
+ body: params,
513
+ signal
514
+ }).then((r) => r)
515
+ );
516
+ }
517
+ /**
518
+ * Remove the per-product config. The product falls back to the
519
+ * seller-level portal config. Returns `{ removed: true }` when a row was
520
+ * deleted, `{ removed: false }` when there was nothing to remove.
521
+ *
522
+ * @example
523
+ * await garu.products.portalConfig.clear(57);
524
+ */
525
+ async clear(productId) {
526
+ return this.http.call(
527
+ (signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
528
+ signal
529
+ }).then((r) => r)
530
+ );
531
+ }
532
+ };
467
533
  var Products = class {
468
534
  constructor(http) {
469
535
  this.http = http;
536
+ this.portalConfig = new ProductPortalConfigResource(http);
470
537
  }
471
538
  http;
539
+ /** Per-product portal customization (Garu v0.8.0). */
540
+ portalConfig;
472
541
  /**
473
542
  * List products for the authenticated seller, with pagination and search.
474
543
  *
@@ -637,13 +706,26 @@ var ScheduledCharges = class {
637
706
  }
638
707
  /**
639
708
  * Manually mark a scheduled charge as paid, e.g. when the customer paid
640
- * outside Garu (bank transfer, cash). Allowed from `due_today` / `overdue`.
709
+ * outside Garu (bank transfer, cash).
710
+ *
711
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
712
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
713
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
641
714
  *
642
715
  * @example
716
+ * // One-time
643
717
  * await garu.scheduledCharges.markPaid('sch_abc123', {
644
718
  * paymentDate: '2026-06-20',
645
719
  * externalReference: 'TED 4472881'
646
720
  * });
721
+ *
722
+ * @example
723
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
724
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
725
+ * cycleNumber: 3,
726
+ * paymentDate: '2026-06-20',
727
+ * externalReference: 'TED 4472881'
728
+ * });
647
729
  */
648
730
  async markPaid(id, params) {
649
731
  return this.http.call(
@@ -653,6 +735,73 @@ var ScheduledCharges = class {
653
735
  }).then((r) => r)
654
736
  );
655
737
  }
738
+ /**
739
+ * Stop future cycles for a recurring series. The currently in-flight
740
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
741
+ * only after that resolves does the series flip to `recurrence_canceled`.
742
+ * Recurring-only.
743
+ *
744
+ * @example
745
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
746
+ * reason: 'cliente cancelou plano'
747
+ * });
748
+ */
749
+ async cancelRecurrence(id, params = {}) {
750
+ return this.http.call(
751
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
752
+ body: params,
753
+ signal
754
+ }).then((r) => r)
755
+ );
756
+ }
757
+ /**
758
+ * Toggle Stripe-style soft cancel on a recurring series. With
759
+ * `enabled: true`, the cycle generator stops emitting new cycles after
760
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
761
+ * Reversible by passing `enabled: false`. Recurring-only.
762
+ *
763
+ * @example
764
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
765
+ */
766
+ async setCancelAtPeriodEnd(id, params) {
767
+ return this.http.call(
768
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
769
+ body: params,
770
+ signal
771
+ }).then((r) => r)
772
+ );
773
+ }
774
+ /**
775
+ * Swap the saved card on a recurring series. The new PaymentMethod must
776
+ * belong to the same customerId. Future cycles silent-charge the new
777
+ * card; the in-flight cycle is not retroactively rebound.
778
+ *
779
+ * @example
780
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
781
+ */
782
+ async changePaymentMethod(id, params) {
783
+ return this.http.call(
784
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
785
+ body: params,
786
+ signal
787
+ }).then((r) => r)
788
+ );
789
+ }
790
+ /**
791
+ * Clear the saved card on a recurring series. Future cycles fall back
792
+ * to the email-with-link flow so the customer can re-enter card details
793
+ * or pay via PIX/Boleto.
794
+ *
795
+ * @example
796
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
797
+ */
798
+ async clearPaymentMethod(id) {
799
+ return this.http.call(
800
+ (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
801
+ signal
802
+ }).then((r) => r)
803
+ );
804
+ }
656
805
  };
657
806
  var webhooks = {
658
807
  verify(params) {
package/dist/index.d.cts CHANGED
@@ -277,7 +277,17 @@ interface ListCustomersParams {
277
277
  }
278
278
  type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
279
  type ScheduledChargeType = 'one_time' | 'recurring';
280
- type ScheduledPaymentMethod = 'pix' | 'boleto';
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
+ }
281
291
  type ScheduledChargeEventType = 'created' | 'postponed' | 'paused' | 'resumed' | 'recurrence_canceled' | 'manually_marked_paid' | 'paid' | 'overdue_reminder_sent' | 'd_day_reminder_sent';
282
292
  type ScheduledChargeActor = {
283
293
  type: 'user';
@@ -346,19 +356,28 @@ interface ScheduledChargeDetail {
346
356
  type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
347
357
  interface CreateScheduledChargeParams {
348
358
  customerId: number;
359
+ /**
360
+ * Required when `methods` includes `card` — Celcoin transactions are
361
+ * scoped per product. Optional otherwise.
362
+ */
349
363
  productId?: number;
350
364
  /** Decimal BRL (e.g. `297.50`). */
351
365
  amount: number;
352
366
  description?: string;
353
- /**
354
- * Schedule type. Only `one_time` is accepted by the current API; the
355
- * literal narrows to that until recurring schedules ship.
356
- */
357
- type: 'one_time';
367
+ /** Schedule type. `recurring` requires a `recurrence` block. */
368
+ type: ScheduledChargeType;
358
369
  /** YYYY-MM-DD in São Paulo time. Must be today or future. */
359
370
  dueDate: string;
360
- /** PIX and Boleto are supported now; card requires tokenization (future). */
371
+ /** `card` is recurring-only and requires `productId`. */
361
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;
362
381
  externalReference?: string;
363
382
  metadata?: Record<string, unknown>;
364
383
  /**
@@ -393,6 +412,22 @@ interface MarkPaidScheduledChargeParams {
393
412
  paymentDate: string;
394
413
  /** Bank reference, internal ID, or any stable string for reconciliation. */
395
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;
396
431
  }
397
432
  interface Product {
398
433
  id: number;
@@ -450,6 +485,98 @@ interface MetaResponse {
450
485
  dashboard_url: string;
451
486
  support_email: string;
452
487
  }
488
+ /**
489
+ * Canonical Garu failure code on `transaction.payment.failed` and
490
+ * `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
491
+ * branch on this rather than the raw Celcoin code.
492
+ */
493
+ type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
494
+ /**
495
+ * Shape of the failure trio added to `transaction.payment.failed` and
496
+ * `scheduled_charge.cycle_failed` payloads. Sellers should always receive
497
+ * a non-null `failureCode` — `unknown` is the sentinel when the gateway
498
+ * didn't surface enough detail to map.
499
+ */
500
+ interface FailurePayload {
501
+ failureCode: GaruFailureCode;
502
+ failureReason: string | null;
503
+ /** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
504
+ gatewayFailureCode: string | null;
505
+ }
506
+ /**
507
+ * `payment_method.expiring_soon` — fires at 30/14/7 days before card
508
+ * expiry, idempotent per stage. Use to nudge the customer to update
509
+ * their card before silent-charge starts failing.
510
+ */
511
+ interface PaymentMethodExpiringPayload {
512
+ paymentMethodId: number;
513
+ customerId: number;
514
+ cardLast4: string;
515
+ cardBrand: string;
516
+ expiresAt: string;
517
+ daysUntilExpiry: 30 | 14 | 7;
518
+ }
519
+ /**
520
+ * `payment_method.expired` — fires once on the day-of-expiry when the cron
521
+ * flips `status='expired'`. Future silent charges short-circuit
522
+ * with `failureCode='card_expired'` instead of hitting the acquirer.
523
+ */
524
+ interface PaymentMethodExpiredPayload {
525
+ paymentMethodId: number;
526
+ customerId: number;
527
+ cardLast4: string;
528
+ cardBrand: string;
529
+ expiresAt: string;
530
+ }
531
+ /**
532
+ * Per-product portal customization (Atletia coach-as-product modeling and
533
+ * any other B2B2C platform). `null` fields inherit from the seller-level
534
+ * portal config.
535
+ */
536
+ interface ProductPortalConfig {
537
+ id: number;
538
+ productId: number;
539
+ businessName: string | null;
540
+ logoUrl: string | null;
541
+ primaryColor: string | null;
542
+ allowCancelSubscription: boolean | null;
543
+ allowUpdatePaymentMethod: boolean | null;
544
+ allowUpdateBillingInfo: boolean | null;
545
+ allowViewInvoices: boolean | null;
546
+ allowApplyCoupons: boolean | null;
547
+ requireCancelReason: boolean | null;
548
+ cancelAtPeriodEndOnly: boolean | null;
549
+ sendCancellationEmail: boolean | null;
550
+ sendPaymentMethodUpdatedEmail: boolean | null;
551
+ customSuccessMessage: string | null;
552
+ customCancellationMessage: string | null;
553
+ customWelcomeText: string | null;
554
+ createdAt: string;
555
+ updatedAt: string;
556
+ }
557
+ /**
558
+ * Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
559
+ * are upsert with merge semantics — only fields present are written;
560
+ * unspecified fields keep their persisted value. Use the `clear`
561
+ * method (DELETE) to reset everything.
562
+ */
563
+ interface SetProductPortalConfigParams {
564
+ businessName?: string | null;
565
+ logoUrl?: string | null;
566
+ primaryColor?: string | null;
567
+ allowCancelSubscription?: boolean | null;
568
+ allowUpdatePaymentMethod?: boolean | null;
569
+ allowUpdateBillingInfo?: boolean | null;
570
+ allowViewInvoices?: boolean | null;
571
+ allowApplyCoupons?: boolean | null;
572
+ requireCancelReason?: boolean | null;
573
+ cancelAtPeriodEndOnly?: boolean | null;
574
+ sendCancellationEmail?: boolean | null;
575
+ sendPaymentMethodUpdatedEmail?: boolean | null;
576
+ customSuccessMessage?: string | null;
577
+ customCancellationMessage?: string | null;
578
+ customWelcomeText?: string | null;
579
+ }
453
580
 
454
581
  /**
455
582
  * Charges — the core of the Garu API.
@@ -622,13 +749,61 @@ declare class Meta {
622
749
  }
623
750
 
624
751
  /**
625
- * Products discover products available to charge.
752
+ * Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
753
+ * that model their professionals/coaches as Products under a single seller
754
+ * and want per-product branding on the customer payment + portal pages.
755
+ */
756
+ declare class ProductPortalConfigResource {
757
+ private readonly http;
758
+ constructor(http: HttpClient);
759
+ /**
760
+ * Get the portal customization for a product. Returns `null` when no
761
+ * per-product config exists (the product falls back to seller-level
762
+ * portal config).
763
+ *
764
+ * @example
765
+ * const cfg = await garu.products.portalConfig.get(57);
766
+ */
767
+ get(productId: number): Promise<ProductPortalConfig | null>;
768
+ /**
769
+ * Create or merge the portal customization (idempotent upsert). Both
770
+ * `set` and `patch` have the same merge semantics — only fields present
771
+ * in the body are written, unspecified fields keep their persisted
772
+ * value. Use `clear` to reset everything.
773
+ *
774
+ * @example
775
+ * await garu.products.portalConfig.set(57, {
776
+ * businessName: 'Coach Maria — Corrida & Trilha',
777
+ * primaryColor: '#257264',
778
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
779
+ * });
780
+ */
781
+ set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
782
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
783
+ patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
784
+ /**
785
+ * Remove the per-product config. The product falls back to the
786
+ * seller-level portal config. Returns `{ removed: true }` when a row was
787
+ * deleted, `{ removed: false }` when there was nothing to remove.
788
+ *
789
+ * @example
790
+ * await garu.products.portalConfig.clear(57);
791
+ */
792
+ clear(productId: number): Promise<{
793
+ removed: boolean;
794
+ }>;
795
+ }
796
+ /**
797
+ * Products — discover products available to charge, and customize the
798
+ * per-product portal experience (v0.8.0).
626
799
  *
627
800
  * Products are scoped to the seller identified by the API key. The UUID
628
801
  * returned here is the same identifier accepted by `charges.create({ productId })`.
629
802
  */
630
803
  declare class Products {
631
804
  private readonly http;
805
+ /** Per-product portal customization (Garu v0.8.0). */
806
+ readonly portalConfig: ProductPortalConfigResource;
632
807
  constructor(http: HttpClient);
633
808
  /**
634
809
  * List products for the authenticated seller, with pagination and search.
@@ -651,13 +826,15 @@ declare class Products {
651
826
  * Scheduled charges — bill a customer on a future date.
652
827
  *
653
828
  * The seller registers a customer (see `garu.customers.create`), then
654
- * schedules one or more charges (PIX or Boleto). Garu drives the rest:
655
- * pre-charge customer email on the due date, dunning to the seller team
656
- * after the due date, and a state machine for postpone/pause/resume/
657
- * mark-paid actions.
829
+ * schedules one or more charges (PIX, Boleto, or Card). Garu drives the
830
+ * rest: pre-charge customer email on the due date, dunning to the seller
831
+ * team after the due date, and a state machine for
832
+ * postpone/pause/resume/mark-paid actions.
658
833
  *
659
- * Recurring schedules are reserved for a future API version; the current
660
- * `type` field accepts only `one_time`.
834
+ * Recurring schedules (`type: 'recurring'`) silent-charge the saved card
835
+ * on every cycle past the first. Optional trial periods, cancel-recurrence,
836
+ * cancel-at-period-end, and payment-method swap actions cover the SaaS
837
+ * lifecycle.
661
838
  */
662
839
  declare class ScheduledCharges {
663
840
  private readonly http;
@@ -732,15 +909,68 @@ declare class ScheduledCharges {
732
909
  resume(id: string): Promise<ScheduledChargeRecord>;
733
910
  /**
734
911
  * Manually mark a scheduled charge as paid, e.g. when the customer paid
735
- * outside Garu (bank transfer, cash). Allowed from `due_today` / `overdue`.
912
+ * outside Garu (bank transfer, cash).
913
+ *
914
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
915
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
916
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
736
917
  *
737
918
  * @example
919
+ * // One-time
738
920
  * await garu.scheduledCharges.markPaid('sch_abc123', {
739
921
  * paymentDate: '2026-06-20',
740
922
  * externalReference: 'TED 4472881'
741
923
  * });
924
+ *
925
+ * @example
926
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
927
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
928
+ * cycleNumber: 3,
929
+ * paymentDate: '2026-06-20',
930
+ * externalReference: 'TED 4472881'
931
+ * });
742
932
  */
743
933
  markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
934
+ /**
935
+ * Stop future cycles for a recurring series. The currently in-flight
936
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
937
+ * only after that resolves does the series flip to `recurrence_canceled`.
938
+ * Recurring-only.
939
+ *
940
+ * @example
941
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
942
+ * reason: 'cliente cancelou plano'
943
+ * });
944
+ */
945
+ cancelRecurrence(id: string, params?: CancelRecurrenceScheduledChargeParams): Promise<ScheduledChargeRecord>;
946
+ /**
947
+ * Toggle Stripe-style soft cancel on a recurring series. With
948
+ * `enabled: true`, the cycle generator stops emitting new cycles after
949
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
950
+ * Reversible by passing `enabled: false`. Recurring-only.
951
+ *
952
+ * @example
953
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
954
+ */
955
+ setCancelAtPeriodEnd(id: string, params: CancelAtPeriodEndScheduledChargeParams): Promise<ScheduledChargeRecord>;
956
+ /**
957
+ * Swap the saved card on a recurring series. The new PaymentMethod must
958
+ * belong to the same customerId. Future cycles silent-charge the new
959
+ * card; the in-flight cycle is not retroactively rebound.
960
+ *
961
+ * @example
962
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
963
+ */
964
+ changePaymentMethod(id: string, params: ChangePaymentMethodScheduledChargeParams): Promise<ScheduledChargeRecord>;
965
+ /**
966
+ * Clear the saved card on a recurring series. Future cycles fall back
967
+ * to the email-with-link flow so the customer can re-enter card details
968
+ * or pay via PIX/Boleto.
969
+ *
970
+ * @example
971
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
972
+ */
973
+ clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
744
974
  }
745
975
 
746
976
  interface GaruOptions {
@@ -841,4 +1071,4 @@ declare class GaruServerError extends GaruAPIError {
841
1071
  constructor(message: string, status: number, requestId: string | null, body: unknown);
842
1072
  }
843
1073
 
844
- export { type CardInfo, 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 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 };
1074
+ 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, type FailurePayload, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, type GaruFailureCode, 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 PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, 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 SetProductPortalConfigParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.d.ts CHANGED
@@ -277,7 +277,17 @@ interface ListCustomersParams {
277
277
  }
278
278
  type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
279
  type ScheduledChargeType = 'one_time' | 'recurring';
280
- type ScheduledPaymentMethod = 'pix' | 'boleto';
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
+ }
281
291
  type ScheduledChargeEventType = 'created' | 'postponed' | 'paused' | 'resumed' | 'recurrence_canceled' | 'manually_marked_paid' | 'paid' | 'overdue_reminder_sent' | 'd_day_reminder_sent';
282
292
  type ScheduledChargeActor = {
283
293
  type: 'user';
@@ -346,19 +356,28 @@ interface ScheduledChargeDetail {
346
356
  type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
347
357
  interface CreateScheduledChargeParams {
348
358
  customerId: number;
359
+ /**
360
+ * Required when `methods` includes `card` — Celcoin transactions are
361
+ * scoped per product. Optional otherwise.
362
+ */
349
363
  productId?: number;
350
364
  /** Decimal BRL (e.g. `297.50`). */
351
365
  amount: number;
352
366
  description?: string;
353
- /**
354
- * Schedule type. Only `one_time` is accepted by the current API; the
355
- * literal narrows to that until recurring schedules ship.
356
- */
357
- type: 'one_time';
367
+ /** Schedule type. `recurring` requires a `recurrence` block. */
368
+ type: ScheduledChargeType;
358
369
  /** YYYY-MM-DD in São Paulo time. Must be today or future. */
359
370
  dueDate: string;
360
- /** PIX and Boleto are supported now; card requires tokenization (future). */
371
+ /** `card` is recurring-only and requires `productId`. */
361
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;
362
381
  externalReference?: string;
363
382
  metadata?: Record<string, unknown>;
364
383
  /**
@@ -393,6 +412,22 @@ interface MarkPaidScheduledChargeParams {
393
412
  paymentDate: string;
394
413
  /** Bank reference, internal ID, or any stable string for reconciliation. */
395
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;
396
431
  }
397
432
  interface Product {
398
433
  id: number;
@@ -450,6 +485,98 @@ interface MetaResponse {
450
485
  dashboard_url: string;
451
486
  support_email: string;
452
487
  }
488
+ /**
489
+ * Canonical Garu failure code on `transaction.payment.failed` and
490
+ * `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
491
+ * branch on this rather than the raw Celcoin code.
492
+ */
493
+ type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
494
+ /**
495
+ * Shape of the failure trio added to `transaction.payment.failed` and
496
+ * `scheduled_charge.cycle_failed` payloads. Sellers should always receive
497
+ * a non-null `failureCode` — `unknown` is the sentinel when the gateway
498
+ * didn't surface enough detail to map.
499
+ */
500
+ interface FailurePayload {
501
+ failureCode: GaruFailureCode;
502
+ failureReason: string | null;
503
+ /** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
504
+ gatewayFailureCode: string | null;
505
+ }
506
+ /**
507
+ * `payment_method.expiring_soon` — fires at 30/14/7 days before card
508
+ * expiry, idempotent per stage. Use to nudge the customer to update
509
+ * their card before silent-charge starts failing.
510
+ */
511
+ interface PaymentMethodExpiringPayload {
512
+ paymentMethodId: number;
513
+ customerId: number;
514
+ cardLast4: string;
515
+ cardBrand: string;
516
+ expiresAt: string;
517
+ daysUntilExpiry: 30 | 14 | 7;
518
+ }
519
+ /**
520
+ * `payment_method.expired` — fires once on the day-of-expiry when the cron
521
+ * flips `status='expired'`. Future silent charges short-circuit
522
+ * with `failureCode='card_expired'` instead of hitting the acquirer.
523
+ */
524
+ interface PaymentMethodExpiredPayload {
525
+ paymentMethodId: number;
526
+ customerId: number;
527
+ cardLast4: string;
528
+ cardBrand: string;
529
+ expiresAt: string;
530
+ }
531
+ /**
532
+ * Per-product portal customization (Atletia coach-as-product modeling and
533
+ * any other B2B2C platform). `null` fields inherit from the seller-level
534
+ * portal config.
535
+ */
536
+ interface ProductPortalConfig {
537
+ id: number;
538
+ productId: number;
539
+ businessName: string | null;
540
+ logoUrl: string | null;
541
+ primaryColor: string | null;
542
+ allowCancelSubscription: boolean | null;
543
+ allowUpdatePaymentMethod: boolean | null;
544
+ allowUpdateBillingInfo: boolean | null;
545
+ allowViewInvoices: boolean | null;
546
+ allowApplyCoupons: boolean | null;
547
+ requireCancelReason: boolean | null;
548
+ cancelAtPeriodEndOnly: boolean | null;
549
+ sendCancellationEmail: boolean | null;
550
+ sendPaymentMethodUpdatedEmail: boolean | null;
551
+ customSuccessMessage: string | null;
552
+ customCancellationMessage: string | null;
553
+ customWelcomeText: string | null;
554
+ createdAt: string;
555
+ updatedAt: string;
556
+ }
557
+ /**
558
+ * Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
559
+ * are upsert with merge semantics — only fields present are written;
560
+ * unspecified fields keep their persisted value. Use the `clear`
561
+ * method (DELETE) to reset everything.
562
+ */
563
+ interface SetProductPortalConfigParams {
564
+ businessName?: string | null;
565
+ logoUrl?: string | null;
566
+ primaryColor?: string | null;
567
+ allowCancelSubscription?: boolean | null;
568
+ allowUpdatePaymentMethod?: boolean | null;
569
+ allowUpdateBillingInfo?: boolean | null;
570
+ allowViewInvoices?: boolean | null;
571
+ allowApplyCoupons?: boolean | null;
572
+ requireCancelReason?: boolean | null;
573
+ cancelAtPeriodEndOnly?: boolean | null;
574
+ sendCancellationEmail?: boolean | null;
575
+ sendPaymentMethodUpdatedEmail?: boolean | null;
576
+ customSuccessMessage?: string | null;
577
+ customCancellationMessage?: string | null;
578
+ customWelcomeText?: string | null;
579
+ }
453
580
 
454
581
  /**
455
582
  * Charges — the core of the Garu API.
@@ -622,13 +749,61 @@ declare class Meta {
622
749
  }
623
750
 
624
751
  /**
625
- * Products discover products available to charge.
752
+ * Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
753
+ * that model their professionals/coaches as Products under a single seller
754
+ * and want per-product branding on the customer payment + portal pages.
755
+ */
756
+ declare class ProductPortalConfigResource {
757
+ private readonly http;
758
+ constructor(http: HttpClient);
759
+ /**
760
+ * Get the portal customization for a product. Returns `null` when no
761
+ * per-product config exists (the product falls back to seller-level
762
+ * portal config).
763
+ *
764
+ * @example
765
+ * const cfg = await garu.products.portalConfig.get(57);
766
+ */
767
+ get(productId: number): Promise<ProductPortalConfig | null>;
768
+ /**
769
+ * Create or merge the portal customization (idempotent upsert). Both
770
+ * `set` and `patch` have the same merge semantics — only fields present
771
+ * in the body are written, unspecified fields keep their persisted
772
+ * value. Use `clear` to reset everything.
773
+ *
774
+ * @example
775
+ * await garu.products.portalConfig.set(57, {
776
+ * businessName: 'Coach Maria — Corrida & Trilha',
777
+ * primaryColor: '#257264',
778
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
779
+ * });
780
+ */
781
+ set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
782
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
783
+ patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
784
+ /**
785
+ * Remove the per-product config. The product falls back to the
786
+ * seller-level portal config. Returns `{ removed: true }` when a row was
787
+ * deleted, `{ removed: false }` when there was nothing to remove.
788
+ *
789
+ * @example
790
+ * await garu.products.portalConfig.clear(57);
791
+ */
792
+ clear(productId: number): Promise<{
793
+ removed: boolean;
794
+ }>;
795
+ }
796
+ /**
797
+ * Products — discover products available to charge, and customize the
798
+ * per-product portal experience (v0.8.0).
626
799
  *
627
800
  * Products are scoped to the seller identified by the API key. The UUID
628
801
  * returned here is the same identifier accepted by `charges.create({ productId })`.
629
802
  */
630
803
  declare class Products {
631
804
  private readonly http;
805
+ /** Per-product portal customization (Garu v0.8.0). */
806
+ readonly portalConfig: ProductPortalConfigResource;
632
807
  constructor(http: HttpClient);
633
808
  /**
634
809
  * List products for the authenticated seller, with pagination and search.
@@ -651,13 +826,15 @@ declare class Products {
651
826
  * Scheduled charges — bill a customer on a future date.
652
827
  *
653
828
  * The seller registers a customer (see `garu.customers.create`), then
654
- * schedules one or more charges (PIX or Boleto). Garu drives the rest:
655
- * pre-charge customer email on the due date, dunning to the seller team
656
- * after the due date, and a state machine for postpone/pause/resume/
657
- * mark-paid actions.
829
+ * schedules one or more charges (PIX, Boleto, or Card). Garu drives the
830
+ * rest: pre-charge customer email on the due date, dunning to the seller
831
+ * team after the due date, and a state machine for
832
+ * postpone/pause/resume/mark-paid actions.
658
833
  *
659
- * Recurring schedules are reserved for a future API version; the current
660
- * `type` field accepts only `one_time`.
834
+ * Recurring schedules (`type: 'recurring'`) silent-charge the saved card
835
+ * on every cycle past the first. Optional trial periods, cancel-recurrence,
836
+ * cancel-at-period-end, and payment-method swap actions cover the SaaS
837
+ * lifecycle.
661
838
  */
662
839
  declare class ScheduledCharges {
663
840
  private readonly http;
@@ -732,15 +909,68 @@ declare class ScheduledCharges {
732
909
  resume(id: string): Promise<ScheduledChargeRecord>;
733
910
  /**
734
911
  * Manually mark a scheduled charge as paid, e.g. when the customer paid
735
- * outside Garu (bank transfer, cash). Allowed from `due_today` / `overdue`.
912
+ * outside Garu (bank transfer, cash).
913
+ *
914
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
915
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
916
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
736
917
  *
737
918
  * @example
919
+ * // One-time
738
920
  * await garu.scheduledCharges.markPaid('sch_abc123', {
739
921
  * paymentDate: '2026-06-20',
740
922
  * externalReference: 'TED 4472881'
741
923
  * });
924
+ *
925
+ * @example
926
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
927
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
928
+ * cycleNumber: 3,
929
+ * paymentDate: '2026-06-20',
930
+ * externalReference: 'TED 4472881'
931
+ * });
742
932
  */
743
933
  markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
934
+ /**
935
+ * Stop future cycles for a recurring series. The currently in-flight
936
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
937
+ * only after that resolves does the series flip to `recurrence_canceled`.
938
+ * Recurring-only.
939
+ *
940
+ * @example
941
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
942
+ * reason: 'cliente cancelou plano'
943
+ * });
944
+ */
945
+ cancelRecurrence(id: string, params?: CancelRecurrenceScheduledChargeParams): Promise<ScheduledChargeRecord>;
946
+ /**
947
+ * Toggle Stripe-style soft cancel on a recurring series. With
948
+ * `enabled: true`, the cycle generator stops emitting new cycles after
949
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
950
+ * Reversible by passing `enabled: false`. Recurring-only.
951
+ *
952
+ * @example
953
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
954
+ */
955
+ setCancelAtPeriodEnd(id: string, params: CancelAtPeriodEndScheduledChargeParams): Promise<ScheduledChargeRecord>;
956
+ /**
957
+ * Swap the saved card on a recurring series. The new PaymentMethod must
958
+ * belong to the same customerId. Future cycles silent-charge the new
959
+ * card; the in-flight cycle is not retroactively rebound.
960
+ *
961
+ * @example
962
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
963
+ */
964
+ changePaymentMethod(id: string, params: ChangePaymentMethodScheduledChargeParams): Promise<ScheduledChargeRecord>;
965
+ /**
966
+ * Clear the saved card on a recurring series. Future cycles fall back
967
+ * to the email-with-link flow so the customer can re-enter card details
968
+ * or pay via PIX/Boleto.
969
+ *
970
+ * @example
971
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
972
+ */
973
+ clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
744
974
  }
745
975
 
746
976
  interface GaruOptions {
@@ -841,4 +1071,4 @@ declare class GaruServerError extends GaruAPIError {
841
1071
  constructor(message: string, status: number, requestId: string | null, body: unknown);
842
1072
  }
843
1073
 
844
- export { type CardInfo, 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 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 };
1074
+ 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, type FailurePayload, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, type GaruFailureCode, 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 PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, 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 SetProductPortalConfigParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.js CHANGED
@@ -458,11 +458,80 @@ var Meta = class {
458
458
  };
459
459
 
460
460
  // src/resources/products.ts
461
+ var ProductPortalConfigResource = class {
462
+ constructor(http) {
463
+ this.http = http;
464
+ }
465
+ http;
466
+ /**
467
+ * Get the portal customization for a product. Returns `null` when no
468
+ * per-product config exists (the product falls back to seller-level
469
+ * portal config).
470
+ *
471
+ * @example
472
+ * const cfg = await garu.products.portalConfig.get(57);
473
+ */
474
+ async get(productId) {
475
+ return this.http.call(
476
+ (signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
477
+ signal
478
+ }).then((r) => r)
479
+ );
480
+ }
481
+ /**
482
+ * Create or merge the portal customization (idempotent upsert). Both
483
+ * `set` and `patch` have the same merge semantics — only fields present
484
+ * in the body are written, unspecified fields keep their persisted
485
+ * value. Use `clear` to reset everything.
486
+ *
487
+ * @example
488
+ * await garu.products.portalConfig.set(57, {
489
+ * businessName: 'Coach Maria — Corrida & Trilha',
490
+ * primaryColor: '#257264',
491
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
492
+ * });
493
+ */
494
+ async set(productId, params) {
495
+ return this.http.call(
496
+ (signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
497
+ body: params,
498
+ signal
499
+ }).then((r) => r)
500
+ );
501
+ }
502
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
503
+ async patch(productId, params) {
504
+ return this.http.call(
505
+ (signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
506
+ body: params,
507
+ signal
508
+ }).then((r) => r)
509
+ );
510
+ }
511
+ /**
512
+ * Remove the per-product config. The product falls back to the
513
+ * seller-level portal config. Returns `{ removed: true }` when a row was
514
+ * deleted, `{ removed: false }` when there was nothing to remove.
515
+ *
516
+ * @example
517
+ * await garu.products.portalConfig.clear(57);
518
+ */
519
+ async clear(productId) {
520
+ return this.http.call(
521
+ (signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
522
+ signal
523
+ }).then((r) => r)
524
+ );
525
+ }
526
+ };
461
527
  var Products = class {
462
528
  constructor(http) {
463
529
  this.http = http;
530
+ this.portalConfig = new ProductPortalConfigResource(http);
464
531
  }
465
532
  http;
533
+ /** Per-product portal customization (Garu v0.8.0). */
534
+ portalConfig;
466
535
  /**
467
536
  * List products for the authenticated seller, with pagination and search.
468
537
  *
@@ -631,13 +700,26 @@ var ScheduledCharges = class {
631
700
  }
632
701
  /**
633
702
  * Manually mark a scheduled charge as paid, e.g. when the customer paid
634
- * outside Garu (bank transfer, cash). Allowed from `due_today` / `overdue`.
703
+ * outside Garu (bank transfer, cash).
704
+ *
705
+ * - **One-time:** omit `cycleNumber`. Allowed from `due_today` / `overdue`.
706
+ * - **Recurring:** pass `cycleNumber`. Allowed from cycle status
707
+ * `due_today` / `overdue` / `failed`. Future cycles continue.
635
708
  *
636
709
  * @example
710
+ * // One-time
637
711
  * await garu.scheduledCharges.markPaid('sch_abc123', {
638
712
  * paymentDate: '2026-06-20',
639
713
  * externalReference: 'TED 4472881'
640
714
  * });
715
+ *
716
+ * @example
717
+ * // Recurring — mark cycle 3 paid; future cycles keep billing
718
+ * await garu.scheduledCharges.markPaid('sch_abc123', {
719
+ * cycleNumber: 3,
720
+ * paymentDate: '2026-06-20',
721
+ * externalReference: 'TED 4472881'
722
+ * });
641
723
  */
642
724
  async markPaid(id, params) {
643
725
  return this.http.call(
@@ -647,6 +729,73 @@ var ScheduledCharges = class {
647
729
  }).then((r) => r)
648
730
  );
649
731
  }
732
+ /**
733
+ * Stop future cycles for a recurring series. The currently in-flight
734
+ * cycle (if any) remains active until paid, postponed, or marked-paid;
735
+ * only after that resolves does the series flip to `recurrence_canceled`.
736
+ * Recurring-only.
737
+ *
738
+ * @example
739
+ * await garu.scheduledCharges.cancelRecurrence('sch_abc123', {
740
+ * reason: 'cliente cancelou plano'
741
+ * });
742
+ */
743
+ async cancelRecurrence(id, params = {}) {
744
+ return this.http.call(
745
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
746
+ body: params,
747
+ signal
748
+ }).then((r) => r)
749
+ );
750
+ }
751
+ /**
752
+ * Toggle Stripe-style soft cancel on a recurring series. With
753
+ * `enabled: true`, the cycle generator stops emitting new cycles after
754
+ * the next paid cycle; the in-flight cycle still bills + can be paid.
755
+ * Reversible by passing `enabled: false`. Recurring-only.
756
+ *
757
+ * @example
758
+ * await garu.scheduledCharges.setCancelAtPeriodEnd('sch_abc123', { enabled: true });
759
+ */
760
+ async setCancelAtPeriodEnd(id, params) {
761
+ return this.http.call(
762
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
763
+ body: params,
764
+ signal
765
+ }).then((r) => r)
766
+ );
767
+ }
768
+ /**
769
+ * Swap the saved card on a recurring series. The new PaymentMethod must
770
+ * belong to the same customerId. Future cycles silent-charge the new
771
+ * card; the in-flight cycle is not retroactively rebound.
772
+ *
773
+ * @example
774
+ * await garu.scheduledCharges.changePaymentMethod('sch_abc123', { paymentMethodId: 42 });
775
+ */
776
+ async changePaymentMethod(id, params) {
777
+ return this.http.call(
778
+ (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
779
+ body: params,
780
+ signal
781
+ }).then((r) => r)
782
+ );
783
+ }
784
+ /**
785
+ * Clear the saved card on a recurring series. Future cycles fall back
786
+ * to the email-with-link flow so the customer can re-enter card details
787
+ * or pay via PIX/Boleto.
788
+ *
789
+ * @example
790
+ * await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
791
+ */
792
+ async clearPaymentMethod(id) {
793
+ return this.http.call(
794
+ (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
795
+ signal
796
+ }).then((r) => r)
797
+ );
798
+ }
650
799
  };
651
800
  var webhooks = {
652
801
  verify(params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.5.0",
3
+ "version": "0.7.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",