@garuhq/node 0.12.1 → 0.13.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,32 @@
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.13.0] — 2026-05-25
7
+
8
+ ### Added
9
+
10
+ - `scheduledCharges.chargeNow(id)` — `POST /api/scheduled-charges/{id}/charge-now`.
11
+ Force-bills the current cycle right now instead of waiting for its due
12
+ date, running the same dispatch the daily billing cron would (customer
13
+ email/notification + outbound webhook + timeline event). Allowed only
14
+ from a billable status (`scheduled` / `due_today`); a recurring series
15
+ must have an open cycle. **Idempotent** — a cycle whose d-day was
16
+ already dispatched reports `already_sent` and does not re-charge.
17
+ Returns `{ outcome, cycleNumber, reason?, message }`:
18
+ - `outcome` is `'dispatched' | 'already_sent' | 'not_sent' | 'failed'`.
19
+ - `reason` (on `not_sent` / `failed`) is one of the documented literals
20
+ (`no_email`, `lock_lost`, `no_saved_payment_method`, `card_expired`,
21
+ `payment_method_missing`, `customer_missing`) or a raw gateway decline
22
+ code.
23
+ - `message` is a ready-to-show pt-BR string.
24
+ - `ChargeNowOutcome`, `ChargeNowReason`, and `ChargeNowResult` types
25
+ exported from the package root.
26
+ - `maxRecoveryDays?: number` (integer 1–365) on
27
+ `CreateScheduledChargeParams` — caps how many days past `dueDate` the
28
+ daily recovery sweep will still auto-bill a missed charge. Omit for the
29
+ system default (14). Also surfaced on the scheduled charge object as
30
+ `ScheduledChargeRecord.maxRecoveryDays: number | null`.
31
+
6
32
  ## [0.12.1] — 2026-05-19
7
33
 
8
34
  ### Fixed
package/README.md CHANGED
@@ -203,6 +203,7 @@ Bill an existing customer on a future date — one-time or recurring with card t
203
203
  | `create(params)` | Create one-time or recurring schedule. Auto-attaches `X-Idempotency-Key`. |
204
204
  | `list(params?)` | Paginated list with status / type / dueFrom / dueTo / customerId filters. |
205
205
  | `get(id)` | Detail bundle: charge + event timeline + linked transactions. |
206
+ | `chargeNow(id)` | Force-bill the current cycle now instead of waiting for the due date. |
206
207
  | `markPaid(id, params)` | Mark cycle paid (off-Garu reconciliation). |
207
208
  | `postpone(id, params)` | Move the next cycle's due date forward. |
208
209
  | `pause(id, params?)` / `resume(id)` | Suspend / re-enable a series. |
@@ -213,7 +214,8 @@ Bill an existing customer on a future date — one-time or recurring with card t
213
214
  | `listAttempts(id, params?)` | Per-attempt billing log — every silent-charge / retry / mark-paid (v0.8.2).|
214
215
 
215
216
  ```ts
216
- // Recurring with 7-day trial
217
+ // Recurring with 7-day trial. `maxRecoveryDays` caps how long past the due
218
+ // date the daily recovery sweep keeps auto-billing a missed charge (default 14).
217
219
  const series = await garu.scheduledCharges.create({
218
220
  customerId: 42,
219
221
  productId: 17,
@@ -223,8 +225,17 @@ const series = await garu.scheduledCharges.create({
223
225
  methods: ['card', 'pix'],
224
226
  recurrence: { interval: 'monthly' },
225
227
  trialDays: 7,
228
+ maxRecoveryDays: 30,
226
229
  });
227
230
 
231
+ // Force-bill the current cycle now instead of waiting for the due date.
232
+ // Idempotent: a cycle already dispatched today reports `already_sent`.
233
+ const result = await garu.scheduledCharges.chargeNow(series.id);
234
+ if (result.outcome === 'failed') {
235
+ // result.reason is e.g. 'card_expired' or a gateway decline code
236
+ console.error(`${result.message} (${result.reason})`);
237
+ }
238
+
228
239
  // Audit why cycle 3 failed (v0.8.2)
229
240
  const { data } = await garu.scheduledCharges.listAttempts(series.id, {
230
241
  cycleNumber: 3,
package/dist/index.cjs CHANGED
@@ -653,9 +653,9 @@ var ScheduledCharges = class {
653
653
  */
654
654
  async get(id) {
655
655
  return this.http.call(
656
- (signal) => this.http.client.GET(`/api/scheduled-charges/${id}`, { signal }).then(
657
- (r) => r
658
- )
656
+ (signal) => this.http.client.GET(`/api/scheduled-charges/${encodeURIComponent(id)}`, {
657
+ signal
658
+ }).then((r) => r)
659
659
  );
660
660
  }
661
661
  /**
@@ -671,10 +671,13 @@ var ScheduledCharges = class {
671
671
  */
672
672
  async postpone(id, params) {
673
673
  return this.http.call(
674
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/postpone`, {
675
- body: params,
676
- signal
677
- }).then((r) => r)
674
+ (signal) => this.http.client.POST(
675
+ `/api/scheduled-charges/${encodeURIComponent(id)}/postpone`,
676
+ {
677
+ body: params,
678
+ signal
679
+ }
680
+ ).then((r) => r)
678
681
  );
679
682
  }
680
683
  /**
@@ -687,10 +690,13 @@ var ScheduledCharges = class {
687
690
  */
688
691
  async pause(id, params = {}) {
689
692
  return this.http.call(
690
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/pause`, {
691
- body: params,
692
- signal
693
- }).then((r) => r)
693
+ (signal) => this.http.client.POST(
694
+ `/api/scheduled-charges/${encodeURIComponent(id)}/pause`,
695
+ {
696
+ body: params,
697
+ signal
698
+ }
699
+ ).then((r) => r)
694
700
  );
695
701
  }
696
702
  /**
@@ -701,10 +707,13 @@ var ScheduledCharges = class {
701
707
  */
702
708
  async resume(id) {
703
709
  return this.http.call(
704
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/resume`, {
705
- body: {},
706
- signal
707
- }).then((r) => r)
710
+ (signal) => this.http.client.POST(
711
+ `/api/scheduled-charges/${encodeURIComponent(id)}/resume`,
712
+ {
713
+ body: {},
714
+ signal
715
+ }
716
+ ).then((r) => r)
708
717
  );
709
718
  }
710
719
  /**
@@ -732,10 +741,52 @@ var ScheduledCharges = class {
732
741
  */
733
742
  async markPaid(id, params) {
734
743
  return this.http.call(
735
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/mark-paid`, {
736
- body: params,
737
- signal
738
- }).then((r) => r)
744
+ (signal) => this.http.client.POST(
745
+ `/api/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
746
+ {
747
+ body: params,
748
+ signal
749
+ }
750
+ ).then((r) => r)
751
+ );
752
+ }
753
+ /**
754
+ * Force-bill the current cycle right now instead of waiting for its due
755
+ * date. Runs the same dispatch the daily billing cron would (customer
756
+ * email/notification + outbound webhook + timeline event). Allowed only
757
+ * from a billable status (`scheduled` / `due_today`); a recurring series
758
+ * must have an open cycle (else the backend returns 400).
759
+ *
760
+ * Idempotent: if this cycle's d-day was already dispatched it reports
761
+ * `already_sent` and does not re-charge. Inspect `outcome` to branch.
762
+ *
763
+ * @example
764
+ * const result = await garu.scheduledCharges.chargeNow('sch_abc123');
765
+ * switch (result.outcome) {
766
+ * case 'dispatched':
767
+ * console.log(`Cobrança enviada (ciclo ${result.cycleNumber}).`);
768
+ * break;
769
+ * case 'already_sent':
770
+ * console.log('Já havia sido enviada — nada a fazer.');
771
+ * break;
772
+ * case 'failed':
773
+ * // result.reason is e.g. 'card_expired' or a gateway decline code
774
+ * console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
775
+ * break;
776
+ * case 'not_sent':
777
+ * console.warn(`Não enviada (${result.reason}): ${result.message}`);
778
+ * break;
779
+ * }
780
+ */
781
+ async chargeNow(id) {
782
+ return this.http.call(
783
+ (signal) => this.http.client.POST(
784
+ `/api/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
785
+ {
786
+ body: {},
787
+ signal
788
+ }
789
+ ).then((r) => r)
739
790
  );
740
791
  }
741
792
  /**
@@ -751,10 +802,13 @@ var ScheduledCharges = class {
751
802
  */
752
803
  async cancelRecurrence(id, params = {}) {
753
804
  return this.http.call(
754
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
755
- body: params,
756
- signal
757
- }).then((r) => r)
805
+ (signal) => this.http.client.POST(
806
+ `/api/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
807
+ {
808
+ body: params,
809
+ signal
810
+ }
811
+ ).then((r) => r)
758
812
  );
759
813
  }
760
814
  /**
@@ -768,10 +822,13 @@ var ScheduledCharges = class {
768
822
  */
769
823
  async setCancelAtPeriodEnd(id, params) {
770
824
  return this.http.call(
771
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
772
- body: params,
773
- signal
774
- }).then((r) => r)
825
+ (signal) => this.http.client.POST(
826
+ `/api/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
827
+ {
828
+ body: params,
829
+ signal
830
+ }
831
+ ).then((r) => r)
775
832
  );
776
833
  }
777
834
  /**
@@ -784,10 +841,13 @@ var ScheduledCharges = class {
784
841
  */
785
842
  async changePaymentMethod(id, params) {
786
843
  return this.http.call(
787
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
788
- body: params,
789
- signal
790
- }).then((r) => r)
844
+ (signal) => this.http.client.POST(
845
+ `/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
846
+ {
847
+ body: params,
848
+ signal
849
+ }
850
+ ).then((r) => r)
791
851
  );
792
852
  }
793
853
  /**
@@ -800,10 +860,13 @@ var ScheduledCharges = class {
800
860
  */
801
861
  async clearPaymentMethod(id) {
802
862
  return this.http.call(
803
- (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
804
- body: {},
805
- signal
806
- }).then((r) => r)
863
+ (signal) => this.http.client.DELETE(
864
+ `/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
865
+ {
866
+ body: {},
867
+ signal
868
+ }
869
+ ).then((r) => r)
807
870
  );
808
871
  }
809
872
  /**
@@ -825,7 +888,7 @@ var ScheduledCharges = class {
825
888
  if (params.limit !== void 0) qs.set("limit", String(params.limit));
826
889
  if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
827
890
  const query = qs.toString();
828
- const url = `/api/scheduled-charges/${id}/attempts${query ? `?${query}` : ""}`;
891
+ const url = `/api/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
829
892
  return this.http.call(
830
893
  (signal) => this.http.client.GET(url, { signal }).then(
831
894
  (r) => r
package/dist/index.d.cts CHANGED
@@ -312,6 +312,11 @@ interface ScheduledChargeRecord {
312
312
  methods: ScheduledPaymentMethod[];
313
313
  status: ScheduledChargeStatus;
314
314
  externalReference: string | null;
315
+ /**
316
+ * Max days past `dueDate` the daily recovery sweep will still auto-bill a
317
+ * missed charge. `null` means the system default (14) applies.
318
+ */
319
+ maxRecoveryDays: number | null;
315
320
  metadata: Record<string, unknown> | null;
316
321
  createdAt: string;
317
322
  updatedAt: string;
@@ -407,6 +412,11 @@ interface CreateScheduledChargeParams {
407
412
  trialDays?: number;
408
413
  externalReference?: string;
409
414
  metadata?: Record<string, unknown>;
415
+ /**
416
+ * Max days past `dueDate` the daily recovery sweep will still auto-bill a
417
+ * missed charge (integer 1..365). Omit for the system default (14).
418
+ */
419
+ maxRecoveryDays?: number;
410
420
  /**
411
421
  * Optional idempotency key for safe retries. The SDK auto-generates a
412
422
  * UUIDv4 when omitted and forwards it as `X-Idempotency-Key`.
@@ -456,6 +466,30 @@ interface ChangePaymentMethodScheduledChargeParams {
456
466
  /** PaymentMethod id to bind. Must belong to the same customerId. */
457
467
  paymentMethodId: number;
458
468
  }
469
+ /**
470
+ * Result of `scheduledCharges.chargeNow(id)` — what the immediate dispatch did:
471
+ *
472
+ * - `dispatched` — sent now (customer email/notification + outbound webhook + timeline event).
473
+ * - `already_sent` — this cycle's d-day was already dispatched; no-op (the action is idempotent).
474
+ * - `not_sent` — couldn't send; see `reason` (e.g. `no_email`, `lock_lost`, `no_saved_payment_method`).
475
+ * - `failed` — card charge failed; see `reason` (e.g. `card_expired`, or a gateway decline code).
476
+ */
477
+ type ChargeNowOutcome = 'dispatched' | 'already_sent' | 'not_sent' | 'failed';
478
+ /**
479
+ * Why a `not_sent` / `failed` charge-now didn't go through. The documented
480
+ * literals are stable; `failed` may also surface a raw gateway decline code,
481
+ * so the type stays open (`string & {}`) without losing autocomplete.
482
+ */
483
+ type ChargeNowReason = 'no_email' | 'lock_lost' | 'no_saved_payment_method' | 'card_expired' | 'payment_method_missing' | 'customer_missing' | (string & {});
484
+ interface ChargeNowResult {
485
+ outcome: ChargeNowOutcome;
486
+ /** Cycle that was dispatched/attempted, or `null` for one-time charges. */
487
+ cycleNumber: number | null;
488
+ /** Present on `not_sent` / `failed`. See {@link ChargeNowReason}. */
489
+ reason?: ChargeNowReason;
490
+ /** Ready-to-show pt-BR message describing the outcome. */
491
+ message: string;
492
+ }
459
493
  interface Product {
460
494
  id: number;
461
495
  uuid: string;
@@ -1035,6 +1069,35 @@ declare class ScheduledCharges {
1035
1069
  * });
1036
1070
  */
1037
1071
  markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
1072
+ /**
1073
+ * Force-bill the current cycle right now instead of waiting for its due
1074
+ * date. Runs the same dispatch the daily billing cron would (customer
1075
+ * email/notification + outbound webhook + timeline event). Allowed only
1076
+ * from a billable status (`scheduled` / `due_today`); a recurring series
1077
+ * must have an open cycle (else the backend returns 400).
1078
+ *
1079
+ * Idempotent: if this cycle's d-day was already dispatched it reports
1080
+ * `already_sent` and does not re-charge. Inspect `outcome` to branch.
1081
+ *
1082
+ * @example
1083
+ * const result = await garu.scheduledCharges.chargeNow('sch_abc123');
1084
+ * switch (result.outcome) {
1085
+ * case 'dispatched':
1086
+ * console.log(`Cobrança enviada (ciclo ${result.cycleNumber}).`);
1087
+ * break;
1088
+ * case 'already_sent':
1089
+ * console.log('Já havia sido enviada — nada a fazer.');
1090
+ * break;
1091
+ * case 'failed':
1092
+ * // result.reason is e.g. 'card_expired' or a gateway decline code
1093
+ * console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
1094
+ * break;
1095
+ * case 'not_sent':
1096
+ * console.warn(`Não enviada (${result.reason}): ${result.message}`);
1097
+ * break;
1098
+ * }
1099
+ */
1100
+ chargeNow(id: string): Promise<ChargeNowResult>;
1038
1101
  /**
1039
1102
  * Stop future cycles for a recurring series. The currently in-flight
1040
1103
  * cycle (if any) remains active until paid, postponed, or marked-paid;
@@ -1289,4 +1352,4 @@ declare class GaruServerError extends GaruAPIError {
1289
1352
  constructor(message: string, status: number, requestId: string | null, body: unknown);
1290
1353
  }
1291
1354
 
1292
- 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 ListScheduledChargeAttemptsParams, type ListScheduledChargesParams, type ListWebhookEventsParams, 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 ResendWebhookEventParams, type ScheduledChargeActor, type ScheduledChargeAttempt, type ScheduledChargeAttemptList, type ScheduledChargeAttemptSource, type ScheduledChargeAttemptStatus, 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 WebhookEvent, type WebhookEventEndpoint, type WebhookEventList, type WebhookEventStatus, type WirePaymentMethodId, webhooks };
1355
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeNowOutcome, type ChargeNowReason, type ChargeNowResult, 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 ListScheduledChargeAttemptsParams, type ListScheduledChargesParams, type ListWebhookEventsParams, 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 ResendWebhookEventParams, type ScheduledChargeActor, type ScheduledChargeAttempt, type ScheduledChargeAttemptList, type ScheduledChargeAttemptSource, type ScheduledChargeAttemptStatus, 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 WebhookEvent, type WebhookEventEndpoint, type WebhookEventList, type WebhookEventStatus, type WirePaymentMethodId, webhooks };
package/dist/index.d.ts CHANGED
@@ -312,6 +312,11 @@ interface ScheduledChargeRecord {
312
312
  methods: ScheduledPaymentMethod[];
313
313
  status: ScheduledChargeStatus;
314
314
  externalReference: string | null;
315
+ /**
316
+ * Max days past `dueDate` the daily recovery sweep will still auto-bill a
317
+ * missed charge. `null` means the system default (14) applies.
318
+ */
319
+ maxRecoveryDays: number | null;
315
320
  metadata: Record<string, unknown> | null;
316
321
  createdAt: string;
317
322
  updatedAt: string;
@@ -407,6 +412,11 @@ interface CreateScheduledChargeParams {
407
412
  trialDays?: number;
408
413
  externalReference?: string;
409
414
  metadata?: Record<string, unknown>;
415
+ /**
416
+ * Max days past `dueDate` the daily recovery sweep will still auto-bill a
417
+ * missed charge (integer 1..365). Omit for the system default (14).
418
+ */
419
+ maxRecoveryDays?: number;
410
420
  /**
411
421
  * Optional idempotency key for safe retries. The SDK auto-generates a
412
422
  * UUIDv4 when omitted and forwards it as `X-Idempotency-Key`.
@@ -456,6 +466,30 @@ interface ChangePaymentMethodScheduledChargeParams {
456
466
  /** PaymentMethod id to bind. Must belong to the same customerId. */
457
467
  paymentMethodId: number;
458
468
  }
469
+ /**
470
+ * Result of `scheduledCharges.chargeNow(id)` — what the immediate dispatch did:
471
+ *
472
+ * - `dispatched` — sent now (customer email/notification + outbound webhook + timeline event).
473
+ * - `already_sent` — this cycle's d-day was already dispatched; no-op (the action is idempotent).
474
+ * - `not_sent` — couldn't send; see `reason` (e.g. `no_email`, `lock_lost`, `no_saved_payment_method`).
475
+ * - `failed` — card charge failed; see `reason` (e.g. `card_expired`, or a gateway decline code).
476
+ */
477
+ type ChargeNowOutcome = 'dispatched' | 'already_sent' | 'not_sent' | 'failed';
478
+ /**
479
+ * Why a `not_sent` / `failed` charge-now didn't go through. The documented
480
+ * literals are stable; `failed` may also surface a raw gateway decline code,
481
+ * so the type stays open (`string & {}`) without losing autocomplete.
482
+ */
483
+ type ChargeNowReason = 'no_email' | 'lock_lost' | 'no_saved_payment_method' | 'card_expired' | 'payment_method_missing' | 'customer_missing' | (string & {});
484
+ interface ChargeNowResult {
485
+ outcome: ChargeNowOutcome;
486
+ /** Cycle that was dispatched/attempted, or `null` for one-time charges. */
487
+ cycleNumber: number | null;
488
+ /** Present on `not_sent` / `failed`. See {@link ChargeNowReason}. */
489
+ reason?: ChargeNowReason;
490
+ /** Ready-to-show pt-BR message describing the outcome. */
491
+ message: string;
492
+ }
459
493
  interface Product {
460
494
  id: number;
461
495
  uuid: string;
@@ -1035,6 +1069,35 @@ declare class ScheduledCharges {
1035
1069
  * });
1036
1070
  */
1037
1071
  markPaid(id: string, params: MarkPaidScheduledChargeParams): Promise<ScheduledChargeRecord>;
1072
+ /**
1073
+ * Force-bill the current cycle right now instead of waiting for its due
1074
+ * date. Runs the same dispatch the daily billing cron would (customer
1075
+ * email/notification + outbound webhook + timeline event). Allowed only
1076
+ * from a billable status (`scheduled` / `due_today`); a recurring series
1077
+ * must have an open cycle (else the backend returns 400).
1078
+ *
1079
+ * Idempotent: if this cycle's d-day was already dispatched it reports
1080
+ * `already_sent` and does not re-charge. Inspect `outcome` to branch.
1081
+ *
1082
+ * @example
1083
+ * const result = await garu.scheduledCharges.chargeNow('sch_abc123');
1084
+ * switch (result.outcome) {
1085
+ * case 'dispatched':
1086
+ * console.log(`Cobrança enviada (ciclo ${result.cycleNumber}).`);
1087
+ * break;
1088
+ * case 'already_sent':
1089
+ * console.log('Já havia sido enviada — nada a fazer.');
1090
+ * break;
1091
+ * case 'failed':
1092
+ * // result.reason is e.g. 'card_expired' or a gateway decline code
1093
+ * console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
1094
+ * break;
1095
+ * case 'not_sent':
1096
+ * console.warn(`Não enviada (${result.reason}): ${result.message}`);
1097
+ * break;
1098
+ * }
1099
+ */
1100
+ chargeNow(id: string): Promise<ChargeNowResult>;
1038
1101
  /**
1039
1102
  * Stop future cycles for a recurring series. The currently in-flight
1040
1103
  * cycle (if any) remains active until paid, postponed, or marked-paid;
@@ -1289,4 +1352,4 @@ declare class GaruServerError extends GaruAPIError {
1289
1352
  constructor(message: string, status: number, requestId: string | null, body: unknown);
1290
1353
  }
1291
1354
 
1292
- 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 ListScheduledChargeAttemptsParams, type ListScheduledChargesParams, type ListWebhookEventsParams, 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 ResendWebhookEventParams, type ScheduledChargeActor, type ScheduledChargeAttempt, type ScheduledChargeAttemptList, type ScheduledChargeAttemptSource, type ScheduledChargeAttemptStatus, 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 WebhookEvent, type WebhookEventEndpoint, type WebhookEventList, type WebhookEventStatus, type WirePaymentMethodId, webhooks };
1355
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeNowOutcome, type ChargeNowReason, type ChargeNowResult, 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 ListScheduledChargeAttemptsParams, type ListScheduledChargesParams, type ListWebhookEventsParams, 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 ResendWebhookEventParams, type ScheduledChargeActor, type ScheduledChargeAttempt, type ScheduledChargeAttemptList, type ScheduledChargeAttemptSource, type ScheduledChargeAttemptStatus, 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 WebhookEvent, type WebhookEventEndpoint, type WebhookEventList, type WebhookEventStatus, type WirePaymentMethodId, webhooks };
package/dist/index.js CHANGED
@@ -647,9 +647,9 @@ var ScheduledCharges = class {
647
647
  */
648
648
  async get(id) {
649
649
  return this.http.call(
650
- (signal) => this.http.client.GET(`/api/scheduled-charges/${id}`, { signal }).then(
651
- (r) => r
652
- )
650
+ (signal) => this.http.client.GET(`/api/scheduled-charges/${encodeURIComponent(id)}`, {
651
+ signal
652
+ }).then((r) => r)
653
653
  );
654
654
  }
655
655
  /**
@@ -665,10 +665,13 @@ var ScheduledCharges = class {
665
665
  */
666
666
  async postpone(id, params) {
667
667
  return this.http.call(
668
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/postpone`, {
669
- body: params,
670
- signal
671
- }).then((r) => r)
668
+ (signal) => this.http.client.POST(
669
+ `/api/scheduled-charges/${encodeURIComponent(id)}/postpone`,
670
+ {
671
+ body: params,
672
+ signal
673
+ }
674
+ ).then((r) => r)
672
675
  );
673
676
  }
674
677
  /**
@@ -681,10 +684,13 @@ var ScheduledCharges = class {
681
684
  */
682
685
  async pause(id, params = {}) {
683
686
  return this.http.call(
684
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/pause`, {
685
- body: params,
686
- signal
687
- }).then((r) => r)
687
+ (signal) => this.http.client.POST(
688
+ `/api/scheduled-charges/${encodeURIComponent(id)}/pause`,
689
+ {
690
+ body: params,
691
+ signal
692
+ }
693
+ ).then((r) => r)
688
694
  );
689
695
  }
690
696
  /**
@@ -695,10 +701,13 @@ var ScheduledCharges = class {
695
701
  */
696
702
  async resume(id) {
697
703
  return this.http.call(
698
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/resume`, {
699
- body: {},
700
- signal
701
- }).then((r) => r)
704
+ (signal) => this.http.client.POST(
705
+ `/api/scheduled-charges/${encodeURIComponent(id)}/resume`,
706
+ {
707
+ body: {},
708
+ signal
709
+ }
710
+ ).then((r) => r)
702
711
  );
703
712
  }
704
713
  /**
@@ -726,10 +735,52 @@ var ScheduledCharges = class {
726
735
  */
727
736
  async markPaid(id, params) {
728
737
  return this.http.call(
729
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/mark-paid`, {
730
- body: params,
731
- signal
732
- }).then((r) => r)
738
+ (signal) => this.http.client.POST(
739
+ `/api/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
740
+ {
741
+ body: params,
742
+ signal
743
+ }
744
+ ).then((r) => r)
745
+ );
746
+ }
747
+ /**
748
+ * Force-bill the current cycle right now instead of waiting for its due
749
+ * date. Runs the same dispatch the daily billing cron would (customer
750
+ * email/notification + outbound webhook + timeline event). Allowed only
751
+ * from a billable status (`scheduled` / `due_today`); a recurring series
752
+ * must have an open cycle (else the backend returns 400).
753
+ *
754
+ * Idempotent: if this cycle's d-day was already dispatched it reports
755
+ * `already_sent` and does not re-charge. Inspect `outcome` to branch.
756
+ *
757
+ * @example
758
+ * const result = await garu.scheduledCharges.chargeNow('sch_abc123');
759
+ * switch (result.outcome) {
760
+ * case 'dispatched':
761
+ * console.log(`Cobrança enviada (ciclo ${result.cycleNumber}).`);
762
+ * break;
763
+ * case 'already_sent':
764
+ * console.log('Já havia sido enviada — nada a fazer.');
765
+ * break;
766
+ * case 'failed':
767
+ * // result.reason is e.g. 'card_expired' or a gateway decline code
768
+ * console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
769
+ * break;
770
+ * case 'not_sent':
771
+ * console.warn(`Não enviada (${result.reason}): ${result.message}`);
772
+ * break;
773
+ * }
774
+ */
775
+ async chargeNow(id) {
776
+ return this.http.call(
777
+ (signal) => this.http.client.POST(
778
+ `/api/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
779
+ {
780
+ body: {},
781
+ signal
782
+ }
783
+ ).then((r) => r)
733
784
  );
734
785
  }
735
786
  /**
@@ -745,10 +796,13 @@ var ScheduledCharges = class {
745
796
  */
746
797
  async cancelRecurrence(id, params = {}) {
747
798
  return this.http.call(
748
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-recurrence`, {
749
- body: params,
750
- signal
751
- }).then((r) => r)
799
+ (signal) => this.http.client.POST(
800
+ `/api/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
801
+ {
802
+ body: params,
803
+ signal
804
+ }
805
+ ).then((r) => r)
752
806
  );
753
807
  }
754
808
  /**
@@ -762,10 +816,13 @@ var ScheduledCharges = class {
762
816
  */
763
817
  async setCancelAtPeriodEnd(id, params) {
764
818
  return this.http.call(
765
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/cancel-at-period-end`, {
766
- body: params,
767
- signal
768
- }).then((r) => r)
819
+ (signal) => this.http.client.POST(
820
+ `/api/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
821
+ {
822
+ body: params,
823
+ signal
824
+ }
825
+ ).then((r) => r)
769
826
  );
770
827
  }
771
828
  /**
@@ -778,10 +835,13 @@ var ScheduledCharges = class {
778
835
  */
779
836
  async changePaymentMethod(id, params) {
780
837
  return this.http.call(
781
- (signal) => this.http.client.POST(`/api/scheduled-charges/${id}/payment-method`, {
782
- body: params,
783
- signal
784
- }).then((r) => r)
838
+ (signal) => this.http.client.POST(
839
+ `/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
840
+ {
841
+ body: params,
842
+ signal
843
+ }
844
+ ).then((r) => r)
785
845
  );
786
846
  }
787
847
  /**
@@ -794,10 +854,13 @@ var ScheduledCharges = class {
794
854
  */
795
855
  async clearPaymentMethod(id) {
796
856
  return this.http.call(
797
- (signal) => this.http.client.DELETE(`/api/scheduled-charges/${id}/payment-method`, {
798
- body: {},
799
- signal
800
- }).then((r) => r)
857
+ (signal) => this.http.client.DELETE(
858
+ `/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
859
+ {
860
+ body: {},
861
+ signal
862
+ }
863
+ ).then((r) => r)
801
864
  );
802
865
  }
803
866
  /**
@@ -819,7 +882,7 @@ var ScheduledCharges = class {
819
882
  if (params.limit !== void 0) qs.set("limit", String(params.limit));
820
883
  if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
821
884
  const query = qs.toString();
822
- const url = `/api/scheduled-charges/${id}/attempts${query ? `?${query}` : ""}`;
885
+ const url = `/api/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
823
886
  return this.http.call(
824
887
  (signal) => this.http.client.GET(url, { signal }).then(
825
888
  (r) => r
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.12.1",
3
+ "version": "0.13.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",
@@ -46,7 +46,7 @@
46
46
  "typecheck": "tsc --noEmit",
47
47
  "test": "vitest run",
48
48
  "test:watch": "vitest",
49
- "generate:fetch": "curl -sf ${GARU_SPEC_URL:-https://garu.com.br/api/swagger-json} -o src/generated/openapi.json",
49
+ "generate:fetch": "curl -sf ${GARU_SPEC_URL:-https://garu.com.br/api/openapi.json} -o src/generated/openapi.json",
50
50
  "generate:filter": "node scripts/filter-spec.mjs",
51
51
  "generate": "npm run generate:fetch && npm run generate:filter && openapi-typescript src/generated/openapi-sdk.json -o src/generated/schema.d.ts",
52
52
  "prepublishOnly": "npm run typecheck && npm test && npm run build"