@garuhq/node 0.13.0 → 0.14.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,36 @@
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.14.0] — 2026-05-31
7
+
8
+ ### Added
9
+
10
+ - **Pix Automático support** — Brazil's BACEN auto-debit recurring Pix, where
11
+ the customer authorizes once via a consent QR/link in their bank app and
12
+ cycles 2+ debit silently. All changes are additive; existing
13
+ Card / Pix / Boleto callers are unaffected.
14
+ - `'pix_automatic'` added to the `ScheduledPaymentMethod` union, so
15
+ `scheduledCharges.create({ methods: ['pix_automatic'], ... })` is now
16
+ typed. Recurring-only and requires `productId` (whose product must have
17
+ Pix Automático enabled).
18
+ - `Product.pixAutomatic: boolean` — when `true`, the public subscription
19
+ checkout exposes Pix Automático. Enabled by default; sellers can disable
20
+ it per product.
21
+ - `'pix_automatic'` added to the `ScheduledChargeAttempt.paymentMethod`
22
+ union and to `WirePaymentMethodId`, so transactions/charges read back
23
+ from Pix Automático cycles type-check.
24
+ - README: new **Pix Automático** section — what it is, when to use it, how to
25
+ enable it on a product, creating a `pix_automatic` scheduled charge, and
26
+ branching webhook handlers on `paymentMethod === 'pix_automatic'`.
27
+
28
+ ### Notes
29
+
30
+ - No new webhook event names: Pix Automático fires the same
31
+ `subscription.*` / `transaction.*` events as card recurrence. Branch on the
32
+ payload's `paymentMethod` field. Refused debits are **not** retried at the
33
+ network level — Garu fires `subscription.payment_failed` and moves the
34
+ series to `past_due`.
35
+
6
36
  ## [0.13.0] — 2026-05-25
7
37
 
8
38
  ### Added
@@ -56,7 +86,7 @@ All notable changes to `@garuhq/node` are documented in this file. Format:
56
86
 
57
87
  - `webhookEvents.resend(id)` — `POST /api/webhook-events/{id}/resend`,
58
88
  the audit-trail-preserving counterpart to `retry()`. The backend
59
- inserts a *clone* event (new numeric id) that points back at the
89
+ inserts a _clone_ event (new numeric id) that points back at the
60
90
  source via `manualResendOf`, then dispatches that clone. The
61
91
  original row is untouched, so the historical record of the prior
62
92
  failure (status, response status/body, attempts) survives. Works on
package/README.md CHANGED
@@ -54,8 +54,8 @@ const charge = await garu.charges.create({
54
54
  name: 'Maria Silva',
55
55
  email: 'maria@exemplo.com.br',
56
56
  document: '12345678909', // CPF, digits only
57
- phone: '11987654321',
58
- },
57
+ phone: '11987654321'
58
+ }
59
59
  });
60
60
 
61
61
  console.log(charge.id, charge.status);
@@ -78,7 +78,7 @@ const garu = new Garu({ apiKey: process.env.GARU_API_KEY });
78
78
  const garu = new Garu({
79
79
  apiKey: process.env.GARU_API_KEY,
80
80
  timeoutMs: 30_000, // default
81
- maxRetries: 2, // default (3 total attempts)
81
+ maxRetries: 2 // default (3 total attempts)
82
82
  });
83
83
  ```
84
84
 
@@ -101,8 +101,8 @@ const charge = await garu.charges.create({
101
101
  name: 'Maria Silva',
102
102
  email: 'maria@exemplo.com.br',
103
103
  document: '12345678909',
104
- phone: '11987654321',
105
- },
104
+ phone: '11987654321'
105
+ }
106
106
  });
107
107
  ```
108
108
 
@@ -117,14 +117,14 @@ const charge = await garu.charges.create({
117
117
  holderName: 'MARIA SILVA',
118
118
  expirationMonth: '12',
119
119
  expirationYear: '2028',
120
- cvv: '123',
120
+ cvv: '123'
121
121
  },
122
122
  customer: {
123
123
  name: 'Maria Silva',
124
124
  email: 'maria@exemplo.com.br',
125
125
  document: '12345678909',
126
- phone: '11987654321',
127
- },
126
+ phone: '11987654321'
127
+ }
128
128
  });
129
129
  ```
130
130
 
@@ -145,13 +145,13 @@ await garu.charges.refund(4472, { amount: 1000 }); // partial refund (R$10.00)
145
145
 
146
146
  ## Customers
147
147
 
148
- | Method | Description |
149
- | ------------------------- | --------------------------------------------- |
150
- | `create(params)` | Create a new customer. |
151
- | `list(params?)` | List customers with pagination and search. |
152
- | `get(id)` | Fetch a single customer by ID. |
153
- | `update(id, params)` | Update a customer's profile. |
154
- | `delete(id)` | Delete a customer. |
148
+ | Method | Description |
149
+ | -------------------- | ------------------------------------------ |
150
+ | `create(params)` | Create a new customer. |
151
+ | `list(params?)` | List customers with pagination and search. |
152
+ | `get(id)` | Fetch a single customer by ID. |
153
+ | `update(id, params)` | Update a customer's profile. |
154
+ | `delete(id)` | Delete a customer. |
155
155
 
156
156
  ```ts
157
157
  const customer = await garu.customers.create({
@@ -159,7 +159,7 @@ const customer = await garu.customers.create({
159
159
  email: 'maria@exemplo.com.br',
160
160
  document: '12345678909',
161
161
  phone: '11987654321',
162
- personType: 'fisica',
162
+ personType: 'fisica'
163
163
  });
164
164
 
165
165
  const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });
@@ -171,26 +171,26 @@ Discover products and customize the per-product portal experience (B2B2C).
171
171
 
172
172
  `portalConfig.*` methods accept `productId` as either the product UUID (preferred — same identifier returned by `list()` and webhook payloads) or the legacy numeric id (Garu v0.10.0+).
173
173
 
174
- | Method | Description |
175
- | ----------------------------------- | ----------------------------------------------------------------- |
176
- | `list(params?)` | Paginated list of products for the seller. |
177
- | `get(uuid)` | Fetch a single product by UUID — same id used by charges. |
178
- | `portalConfig.get(productId)` | Read per-product portal customization. Returns `null` if unset. |
179
- | `portalConfig.set(productId, p)` | Upsert with merge — only fields present are written. |
180
- | `portalConfig.patch(productId, p)` | Same merge semantics as `set` — alias for HTTP-PATCH callers. |
181
- | `portalConfig.clear(productId)` | Remove the customization; product falls back to seller config. |
174
+ | Method | Description |
175
+ | ---------------------------------- | --------------------------------------------------------------- |
176
+ | `list(params?)` | Paginated list of products for the seller. |
177
+ | `get(uuid)` | Fetch a single product by UUID — same id used by charges. |
178
+ | `portalConfig.get(productId)` | Read per-product portal customization. Returns `null` if unset. |
179
+ | `portalConfig.set(productId, p)` | Upsert with merge — only fields present are written. |
180
+ | `portalConfig.patch(productId, p)` | Same merge semantics as `set` — alias for HTTP-PATCH callers. |
181
+ | `portalConfig.clear(productId)` | Remove the customization; product falls back to seller config. |
182
182
 
183
183
  ```ts
184
184
  // SaaS de coaching: per-coach branding under one Seller account
185
185
  await garu.products.portalConfig.set('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f', {
186
186
  businessName: 'Coach Maria — Corrida & Trilha',
187
187
  primaryColor: '#257264',
188
- logoUrl: 'https://cdn.exemplo.com/coaches/maria.png',
188
+ logoUrl: 'https://cdn.exemplo.com/coaches/maria.png'
189
189
  });
190
190
 
191
191
  // Pass `null` on a field to inherit from the seller-level config
192
192
  await garu.products.portalConfig.patch('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f', {
193
- primaryColor: null,
193
+ primaryColor: null
194
194
  });
195
195
  ```
196
196
 
@@ -198,20 +198,20 @@ await garu.products.portalConfig.patch('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f', {
198
198
 
199
199
  Bill an existing customer on a future date — one-time or recurring with card tokenization. The Garu drives email reminders, dunning, retries, and the lifecycle state machine.
200
200
 
201
- | Method | Description |
202
- | --------------------------------------------- | -------------------------------------------------------------------------- |
203
- | `create(params)` | Create one-time or recurring schedule. Auto-attaches `X-Idempotency-Key`. |
204
- | `list(params?)` | Paginated list with status / type / dueFrom / dueTo / customerId filters. |
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. |
207
- | `markPaid(id, params)` | Mark cycle paid (off-Garu reconciliation). |
208
- | `postpone(id, params)` | Move the next cycle's due date forward. |
209
- | `pause(id, params?)` / `resume(id)` | Suspend / re-enable a series. |
210
- | `cancelRecurrence(id, params?)` | Hard-stop future cycles (recurring only). |
211
- | `cancelAtPeriodEnd(id, { enabled })` | Stripe-style soft-cancel; reversible. |
212
- | `changePaymentMethod(id, params)` | Swap the saved card. |
213
- | `clearPaymentMethod(id)` | Remove the saved card; future cycles email-with-link. |
214
- | `listAttempts(id, params?)` | Per-attempt billing log — every silent-charge / retry / mark-paid (v0.8.2).|
201
+ | Method | Description |
202
+ | ------------------------------------ | --------------------------------------------------------------------------- |
203
+ | `create(params)` | Create one-time or recurring schedule. Auto-attaches `X-Idempotency-Key`. |
204
+ | `list(params?)` | Paginated list with status / type / dueFrom / dueTo / customerId filters. |
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. |
207
+ | `markPaid(id, params)` | Mark cycle paid (off-Garu reconciliation). |
208
+ | `postpone(id, params)` | Move the next cycle's due date forward. |
209
+ | `pause(id, params?)` / `resume(id)` | Suspend / re-enable a series. |
210
+ | `cancelRecurrence(id, params?)` | Hard-stop future cycles (recurring only). |
211
+ | `cancelAtPeriodEnd(id, { enabled })` | Stripe-style soft-cancel; reversible. |
212
+ | `changePaymentMethod(id, params)` | Swap the saved card. |
213
+ | `clearPaymentMethod(id)` | Remove the saved card; future cycles email-with-link. |
214
+ | `listAttempts(id, params?)` | Per-attempt billing log — every silent-charge / retry / mark-paid (v0.8.2). |
215
215
 
216
216
  ```ts
217
217
  // Recurring with 7-day trial. `maxRecoveryDays` caps how long past the due
@@ -225,7 +225,7 @@ const series = await garu.scheduledCharges.create({
225
225
  methods: ['card', 'pix'],
226
226
  recurrence: { interval: 'monthly' },
227
227
  trialDays: 7,
228
- maxRecoveryDays: 30,
228
+ maxRecoveryDays: 30
229
229
  });
230
230
 
231
231
  // Force-bill the current cycle now instead of waiting for the due date.
@@ -238,7 +238,7 @@ if (result.outcome === 'failed') {
238
238
 
239
239
  // Audit why cycle 3 failed (v0.8.2)
240
240
  const { data } = await garu.scheduledCharges.listAttempts(series.id, {
241
- cycleNumber: 3,
241
+ cycleNumber: 3
242
242
  });
243
243
  const declines = data.filter((a) => a.status === 'declined');
244
244
  // → each declines[i].failureCode is one of GaruFailureCode (insufficient_funds,
@@ -264,6 +264,83 @@ function shouldAskForNewCard(code: GaruFailureCode): boolean {
264
264
 
265
265
  Full table at [docs.garu.com.br/api-reference/webhooks/codigos-de-falha](https://docs.garu.com.br/api-reference/webhooks/codigos-de-falha).
266
266
 
267
+ ## Pix Automático
268
+
269
+ Pix Automático is Brazil's BACEN auto-debit recurring Pix. The customer authorizes **once** — they open their bank app, find the "Pix Automático" / "Recorrência Pix" section, and approve a consent QR/link. Every cycle from the second onward debits silently, with no further customer action.
270
+
271
+ **When to use it:** recurring billing where you want bank-level auto-debit instead of a saved card — subscriptions, mensalidades, memberships. Use card recurrence when you need installments or international cards; use Pix Automático for low-friction domestic recurring Pix.
272
+
273
+ It rides the **same SDK surface** as card-backed recurrence — no new methods, no new webhook events. The only differences are the `pix_automatic` method literal and a per-product enable flag.
274
+
275
+ ### 1. Enable it on a product
276
+
277
+ Pix Automático only shows up on a product's checkout when the product has it enabled (`Product.pixAutomatic`). This is a property of the product (managed in the dashboard / product API); the SDK surfaces it as a boolean:
278
+
279
+ ```ts
280
+ const product = await garu.products.get('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f');
281
+ if (!product.pixAutomatic) {
282
+ // Pix Automático is off for this product — enable it before scheduling a
283
+ // `pix_automatic` charge, or the create call will 400.
284
+ }
285
+ ```
286
+
287
+ ### 2. Create a Pix Automático scheduled charge
288
+
289
+ `pix_automatic` is **recurring-only** and **requires `productId`** (the product must have `pixAutomatic` enabled). The charge starts in a waiting state until the customer approves the consent; cycles 2+ then debit silently.
290
+
291
+ ```ts
292
+ const series = await garu.scheduledCharges.create({
293
+ customerId: 42,
294
+ productId: 17,
295
+ amount: 49.9,
296
+ type: 'recurring',
297
+ dueDate: '2026-06-15',
298
+ methods: ['pix_automatic'],
299
+ recurrence: { interval: 'monthly' }
300
+ });
301
+ ```
302
+
303
+ Cancel and the rest of the lifecycle use the **same methods** as card-backed series — `cancelRecurrence(id)`, `cancelAtPeriodEnd(id, { enabled })`, `pause(id)` / `resume(id)`. The customer can also revoke the authorization directly in their bank app; Garu surfaces that as a `subscription.cancelled` event.
304
+
305
+ ### 3. Handle the webhooks
306
+
307
+ Pix Automático fires the **same events** as card recurrence — there are no Pix-Automático-specific event names. Branch on the payload's `paymentMethod` field (`'pix_automatic'`) when you need method-specific handling:
308
+
309
+ ```ts
310
+ app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res) => {
311
+ const { event } = Garu.webhooks.verify({
312
+ payload: req.body,
313
+ signature: req.header('x-garu-signature') ?? '',
314
+ secret: process.env.GARU_WEBHOOK_SECRET!
315
+ });
316
+
317
+ // `event` is the verified payload. It carries the Garu `eventType` and a
318
+ // `paymentMethod` field; branch on `paymentMethod` to special-case Pix
319
+ // Automático. (Field paths follow your webhook payload reference.)
320
+ const { eventType, paymentMethod } = event as {
321
+ eventType?: string;
322
+ paymentMethod?: string;
323
+ };
324
+
325
+ if (paymentMethod === 'pix_automatic') {
326
+ switch (eventType) {
327
+ case 'transaction.payment.succeeded':
328
+ // a Pix Automático cycle debited
329
+ break;
330
+ case 'subscription.payment_failed':
331
+ // Pix Automático does NOT retry a refused debit at the network level —
332
+ // Garu flips the series to `past_due` and the usual dunning applies.
333
+ break;
334
+ }
335
+ }
336
+
337
+ res.sendStatus(200);
338
+ });
339
+ ```
340
+
341
+ > [!NOTE]
342
+ > Failure model: Pix Automático does not retry a refused debit at the payment-network level. On a refused cycle Garu fires `subscription.payment_failed` and moves the series to `past_due`; your existing dunning handles recovery.
343
+
267
344
  ## Meta
268
345
 
269
346
  Discover available payment methods and webhook events. No authentication required.
@@ -288,7 +365,7 @@ app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res)
288
365
  const { event } = Garu.webhooks.verify({
289
366
  payload: req.body, // raw Buffer — do NOT re-serialize parsed JSON
290
367
  signature: req.header('x-garu-signature') ?? '',
291
- secret: process.env.GARU_WEBHOOK_SECRET!,
368
+ secret: process.env.GARU_WEBHOOK_SECRET!
292
369
  });
293
370
 
294
371
  console.log('Received', event);
@@ -305,7 +382,7 @@ app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res)
305
382
 
306
383
  ## Webhook events
307
384
 
308
- The seller-facing delivery log for outbound webhooks. Use it to audit deliveries, surface failures, and replay events when a customer's endpoint missed one. Webhook endpoint *configuration* (URL, subscribed events, secret) is still dashboard-only — this resource only covers the event log + manual retries.
385
+ The seller-facing delivery log for outbound webhooks. Use it to audit deliveries, surface failures, and replay events when a customer's endpoint missed one. Webhook endpoint _configuration_ (URL, subscribed events, secret) is still dashboard-only — this resource only covers the event log + manual retries.
309
386
 
310
387
  ```ts
311
388
  // Surface anything that didn't make it through
@@ -317,7 +394,7 @@ console.log(event.responseStatus, event.responseBody);
317
394
 
318
395
  // Audit-trail-preserving replay (recommended)
319
396
  const clone = await garu.webhookEvents.resend(42);
320
- clone.id !== event.id; // true — fresh row with its own id
397
+ clone.id !== event.id; // true — fresh row with its own id
321
398
  clone.manualResendOf === event.id; // true — points back at the source
322
399
  ```
323
400
 
@@ -328,12 +405,12 @@ Outbound deliveries of a resent event carry `Idempotency-Key: resend_<originalId
328
405
  > [!NOTE]
329
406
  > The SDK auto-attaches `X-Idempotency-Key` (UUIDv4) on `resend()` so transient transport retries can't create duplicate clones. Pass `{ idempotencyKey }` to dedupe across your own retry layer.
330
407
 
331
- | Method | Purpose |
332
- | ------------------------------- | ---------------------------------------------------------------------------------- |
333
- | `list(params?)` | Paginated event log. Filter by `status`, `eventType`, `endpointId`. Newest first. |
334
- | `get(id)` | One event — full payload, endpoint snapshot, most recent response. |
335
- | `resend(id, params?)` | Clone-on-resend. Returns the new event; original is untouched. **Preferred.** |
336
- | `retry(id)` | Legacy in-place reset (mutates the original row). Soft-deprecated. |
408
+ | Method | Purpose |
409
+ | --------------------- | --------------------------------------------------------------------------------- |
410
+ | `list(params?)` | Paginated event log. Filter by `status`, `eventType`, `endpointId`. Newest first. |
411
+ | `get(id)` | One event — full payload, endpoint snapshot, most recent response. |
412
+ | `resend(id, params?)` | Clone-on-resend. Returns the new event; original is untouched. **Preferred.** |
413
+ | `retry(id)` | Legacy in-place reset (mutates the original row). Soft-deprecated. |
337
414
 
338
415
  ## Error handling
339
416
 
@@ -344,7 +421,7 @@ import {
344
421
  GaruAPIError,
345
422
  GaruNotFoundError,
346
423
  GaruRateLimitError,
347
- GaruValidationError,
424
+ GaruValidationError
348
425
  } from '@garuhq/node';
349
426
 
350
427
  try {
@@ -365,16 +442,16 @@ try {
365
442
  }
366
443
  ```
367
444
 
368
- | Error class | HTTP status |
369
- | ----------------------------------- | ------------------ |
370
- | `GaruAuthenticationError` | `401` |
371
- | `GaruPermissionError` | `403` |
372
- | `GaruNotFoundError` | `404` |
373
- | `GaruValidationError` | `400` / `422` |
374
- | `GaruRateLimitError` | `429` |
375
- | `GaruServerError` | `5xx` |
376
- | `GaruConnectionError` | Network failure |
377
- | `GaruSignatureVerificationError` | Webhook mismatch |
445
+ | Error class | HTTP status |
446
+ | -------------------------------- | ---------------- |
447
+ | `GaruAuthenticationError` | `401` |
448
+ | `GaruPermissionError` | `403` |
449
+ | `GaruNotFoundError` | `404` |
450
+ | `GaruValidationError` | `400` / `422` |
451
+ | `GaruRateLimitError` | `429` |
452
+ | `GaruServerError` | `5xx` |
453
+ | `GaruConnectionError` | Network failure |
454
+ | `GaruSignatureVerificationError` | Webhook mismatch |
378
455
 
379
456
  ## Retries
380
457
 
@@ -392,7 +469,7 @@ import type {
392
469
  Customer,
393
470
  CardInfo,
394
471
  PaymentMethod,
395
- MetaResponse,
472
+ MetaResponse
396
473
  } from '@garuhq/node';
397
474
  ```
398
475
 
package/dist/index.cjs CHANGED
@@ -596,6 +596,20 @@ var ScheduledCharges = class {
596
596
  * methods: ['pix', 'boleto'],
597
597
  * description: 'Mensalidade Junho'
598
598
  * });
599
+ *
600
+ * @example
601
+ * // Pix Automático (BACEN auto-debit). Requires `type: 'recurring'` and a
602
+ * // `productId` whose product has Pix Automático enabled. The customer
603
+ * // authorizes once via their bank app; cycles 2+ debit silently.
604
+ * const series = await garu.scheduledCharges.create({
605
+ * customerId: 42,
606
+ * productId: 17,
607
+ * amount: 49.9,
608
+ * type: 'recurring',
609
+ * dueDate: '2026-06-15',
610
+ * methods: ['pix_automatic'],
611
+ * recurrence: { interval: 'monthly' }
612
+ * });
599
613
  */
600
614
  async create(params) {
601
615
  const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
package/dist/index.d.cts CHANGED
@@ -99,8 +99,13 @@ declare class HttpClient {
99
99
  */
100
100
 
101
101
  type PaymentMethod = 'pix' | 'credit_card' | 'boleto';
102
- /** Payment-method identifier as sent to the backend over the wire. */
103
- type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto';
102
+ /**
103
+ * Payment-method identifier as it appears on the wire. `pix_automatic`
104
+ * (Pix Automático auto-debit) surfaces here on transactions/charges read
105
+ * back from Pix Automático recurring cycles. It is never produced by
106
+ * `toWirePaymentMethod`, since one-off charges can't use it.
107
+ */
108
+ type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto' | 'pix_automatic';
104
109
  type ChargeStatus = 'pending' | 'authorized' | 'paid' | 'failed' | 'refunded' | 'cancelled' | 'expired';
105
110
  interface Customer {
106
111
  /** Full legal name. 3–255 chars. */
@@ -277,7 +282,16 @@ interface ListCustomersParams {
277
282
  }
278
283
  type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
284
  type ScheduledChargeType = 'one_time' | 'recurring';
280
- type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card';
285
+ /**
286
+ * Payment method for a scheduled charge.
287
+ *
288
+ * `pix_automatic` is Pix Automático — Brazil's BACEN auto-debit recurring
289
+ * Pix. The customer authorizes **once** via a consent link/QR in their bank
290
+ * app; every cycle from the second onward debits silently with no further
291
+ * action. It is only valid when `type='recurring'` **and** `productId` is
292
+ * set; the product must also have Pix Automático enabled (`pixAutomatic`).
293
+ */
294
+ type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card' | 'pix_automatic';
281
295
  type RecurrenceInterval = 'weekly' | 'biweekly' | 'monthly' | 'bimonthly' | 'quarterly' | 'biannual' | 'yearly';
282
296
  interface RecurrenceConfig {
283
297
  interval: RecurrenceInterval;
@@ -369,7 +383,7 @@ interface ScheduledChargeAttempt {
369
383
  attemptNumber: number;
370
384
  attemptedAt: string;
371
385
  source: ScheduledChargeAttemptSource;
372
- paymentMethod: 'card' | 'pix' | 'boleto' | 'manual';
386
+ paymentMethod: 'card' | 'pix' | 'boleto' | 'pix_automatic' | 'manual';
373
387
  paymentMethodId: number | null;
374
388
  cardLast4: string | null;
375
389
  cardBrand: string | null;
@@ -400,7 +414,11 @@ interface CreateScheduledChargeParams {
400
414
  type: ScheduledChargeType;
401
415
  /** YYYY-MM-DD in São Paulo time. Must be today or future. */
402
416
  dueDate: string;
403
- /** `card` is recurring-only and requires `productId`. */
417
+ /**
418
+ * `card` is recurring-only and requires `productId`. `pix_automatic`
419
+ * (Pix Automático auto-debit) likewise requires `type='recurring'` **and**
420
+ * `productId`, and the product must have Pix Automático enabled.
421
+ */
404
422
  methods: ScheduledPaymentMethod[];
405
423
  /** Cadence for `type='recurring'`. Must be omitted when `type='one_time'`. */
406
424
  recurrence?: RecurrenceConfig;
@@ -503,6 +521,13 @@ interface Product {
503
521
  pix: boolean;
504
522
  boleto: boolean;
505
523
  creditCard: boolean;
524
+ /**
525
+ * When `true`, the public subscription checkout exposes Pix Automático
526
+ * (BACEN auto-debit recurring Pix) as a payment option. Enabled by
527
+ * default; sellers can disable it per product. Only the subscription
528
+ * checkout mode reads this flag. See {@link ScheduledPaymentMethod}.
529
+ */
530
+ pixAutomatic: boolean;
506
531
  installments: number[];
507
532
  tags?: string[];
508
533
  isSubscription?: boolean;
@@ -991,6 +1016,20 @@ declare class ScheduledCharges {
991
1016
  * methods: ['pix', 'boleto'],
992
1017
  * description: 'Mensalidade Junho'
993
1018
  * });
1019
+ *
1020
+ * @example
1021
+ * // Pix Automático (BACEN auto-debit). Requires `type: 'recurring'` and a
1022
+ * // `productId` whose product has Pix Automático enabled. The customer
1023
+ * // authorizes once via their bank app; cycles 2+ debit silently.
1024
+ * const series = await garu.scheduledCharges.create({
1025
+ * customerId: 42,
1026
+ * productId: 17,
1027
+ * amount: 49.9,
1028
+ * type: 'recurring',
1029
+ * dueDate: '2026-06-15',
1030
+ * methods: ['pix_automatic'],
1031
+ * recurrence: { interval: 'monthly' }
1032
+ * });
994
1033
  */
995
1034
  create(params: CreateScheduledChargeParams): Promise<ScheduledChargeRecord>;
996
1035
  /**
package/dist/index.d.ts CHANGED
@@ -99,8 +99,13 @@ declare class HttpClient {
99
99
  */
100
100
 
101
101
  type PaymentMethod = 'pix' | 'credit_card' | 'boleto';
102
- /** Payment-method identifier as sent to the backend over the wire. */
103
- type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto';
102
+ /**
103
+ * Payment-method identifier as it appears on the wire. `pix_automatic`
104
+ * (Pix Automático auto-debit) surfaces here on transactions/charges read
105
+ * back from Pix Automático recurring cycles. It is never produced by
106
+ * `toWirePaymentMethod`, since one-off charges can't use it.
107
+ */
108
+ type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto' | 'pix_automatic';
104
109
  type ChargeStatus = 'pending' | 'authorized' | 'paid' | 'failed' | 'refunded' | 'cancelled' | 'expired';
105
110
  interface Customer {
106
111
  /** Full legal name. 3–255 chars. */
@@ -277,7 +282,16 @@ interface ListCustomersParams {
277
282
  }
278
283
  type ScheduledChargeStatus = 'scheduled' | 'due_today' | 'overdue' | 'paid' | 'paused' | 'canceled' | 'trial' | 'pending_tokenization' | 'recurrence_canceled';
279
284
  type ScheduledChargeType = 'one_time' | 'recurring';
280
- type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card';
285
+ /**
286
+ * Payment method for a scheduled charge.
287
+ *
288
+ * `pix_automatic` is Pix Automático — Brazil's BACEN auto-debit recurring
289
+ * Pix. The customer authorizes **once** via a consent link/QR in their bank
290
+ * app; every cycle from the second onward debits silently with no further
291
+ * action. It is only valid when `type='recurring'` **and** `productId` is
292
+ * set; the product must also have Pix Automático enabled (`pixAutomatic`).
293
+ */
294
+ type ScheduledPaymentMethod = 'pix' | 'boleto' | 'card' | 'pix_automatic';
281
295
  type RecurrenceInterval = 'weekly' | 'biweekly' | 'monthly' | 'bimonthly' | 'quarterly' | 'biannual' | 'yearly';
282
296
  interface RecurrenceConfig {
283
297
  interval: RecurrenceInterval;
@@ -369,7 +383,7 @@ interface ScheduledChargeAttempt {
369
383
  attemptNumber: number;
370
384
  attemptedAt: string;
371
385
  source: ScheduledChargeAttemptSource;
372
- paymentMethod: 'card' | 'pix' | 'boleto' | 'manual';
386
+ paymentMethod: 'card' | 'pix' | 'boleto' | 'pix_automatic' | 'manual';
373
387
  paymentMethodId: number | null;
374
388
  cardLast4: string | null;
375
389
  cardBrand: string | null;
@@ -400,7 +414,11 @@ interface CreateScheduledChargeParams {
400
414
  type: ScheduledChargeType;
401
415
  /** YYYY-MM-DD in São Paulo time. Must be today or future. */
402
416
  dueDate: string;
403
- /** `card` is recurring-only and requires `productId`. */
417
+ /**
418
+ * `card` is recurring-only and requires `productId`. `pix_automatic`
419
+ * (Pix Automático auto-debit) likewise requires `type='recurring'` **and**
420
+ * `productId`, and the product must have Pix Automático enabled.
421
+ */
404
422
  methods: ScheduledPaymentMethod[];
405
423
  /** Cadence for `type='recurring'`. Must be omitted when `type='one_time'`. */
406
424
  recurrence?: RecurrenceConfig;
@@ -503,6 +521,13 @@ interface Product {
503
521
  pix: boolean;
504
522
  boleto: boolean;
505
523
  creditCard: boolean;
524
+ /**
525
+ * When `true`, the public subscription checkout exposes Pix Automático
526
+ * (BACEN auto-debit recurring Pix) as a payment option. Enabled by
527
+ * default; sellers can disable it per product. Only the subscription
528
+ * checkout mode reads this flag. See {@link ScheduledPaymentMethod}.
529
+ */
530
+ pixAutomatic: boolean;
506
531
  installments: number[];
507
532
  tags?: string[];
508
533
  isSubscription?: boolean;
@@ -991,6 +1016,20 @@ declare class ScheduledCharges {
991
1016
  * methods: ['pix', 'boleto'],
992
1017
  * description: 'Mensalidade Junho'
993
1018
  * });
1019
+ *
1020
+ * @example
1021
+ * // Pix Automático (BACEN auto-debit). Requires `type: 'recurring'` and a
1022
+ * // `productId` whose product has Pix Automático enabled. The customer
1023
+ * // authorizes once via their bank app; cycles 2+ debit silently.
1024
+ * const series = await garu.scheduledCharges.create({
1025
+ * customerId: 42,
1026
+ * productId: 17,
1027
+ * amount: 49.9,
1028
+ * type: 'recurring',
1029
+ * dueDate: '2026-06-15',
1030
+ * methods: ['pix_automatic'],
1031
+ * recurrence: { interval: 'monthly' }
1032
+ * });
994
1033
  */
995
1034
  create(params: CreateScheduledChargeParams): Promise<ScheduledChargeRecord>;
996
1035
  /**
package/dist/index.js CHANGED
@@ -590,6 +590,20 @@ var ScheduledCharges = class {
590
590
  * methods: ['pix', 'boleto'],
591
591
  * description: 'Mensalidade Junho'
592
592
  * });
593
+ *
594
+ * @example
595
+ * // Pix Automático (BACEN auto-debit). Requires `type: 'recurring'` and a
596
+ * // `productId` whose product has Pix Automático enabled. The customer
597
+ * // authorizes once via their bank app; cycles 2+ debit silently.
598
+ * const series = await garu.scheduledCharges.create({
599
+ * customerId: 42,
600
+ * productId: 17,
601
+ * amount: 49.9,
602
+ * type: 'recurring',
603
+ * dueDate: '2026-06-15',
604
+ * methods: ['pix_automatic'],
605
+ * recurrence: { interval: 'monthly' }
606
+ * });
593
607
  */
594
608
  async create(params) {
595
609
  const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.13.0",
3
+ "version": "0.14.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",