@garuhq/node 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -14
- package/README.md +29 -22
- package/dist/index.cjs +24 -22
- package/dist/index.d.cts +34 -12
- package/dist/index.d.ts +34 -12
- package/dist/index.js +24 -22
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,54 @@
|
|
|
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
|
+
## [4.0.0] — 2026-08-22
|
|
7
|
+
|
|
8
|
+
**Breaking:** `scheduledCharges` now targets the versioned public API
|
|
9
|
+
`/api/v1/scheduled-charges`. `id` was already a stable, non-enumerable
|
|
10
|
+
string (`sch_...`) — no identifier change — but the list envelope shape
|
|
11
|
+
changed. If you use `garu.scheduledCharges.*`, read the migration below.
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
|
|
15
|
+
- **`scheduledCharges` moved to `/api/v1/scheduled-charges`.**
|
|
16
|
+
- **`scheduledCharges.list()` and `.listAttempts()` now return
|
|
17
|
+
`{ data, count, totalCount, totalPages }`** (was `{ data, meta }`).
|
|
18
|
+
- No method signatures changed — every method already took/returned the
|
|
19
|
+
same shapes, since `id` was never a numeric internal id here.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `ScheduledChargeRecord` now explicitly types `recurrence`,
|
|
24
|
+
`cancelAtPeriodEnd`, `trialEndsAt`, and `subscriptionId` (previously only
|
|
25
|
+
reachable via the type's index signature, untyped).
|
|
26
|
+
- Test coverage for `cancelRecurrence`, `setCancelAtPeriodEnd`,
|
|
27
|
+
`changePaymentMethod`, `clearPaymentMethod`, and `listAttempts` — none of
|
|
28
|
+
these five methods had a single test before this release.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- `ScheduledChargeLinkedTransaction.value`'s docstring claimed centavos;
|
|
33
|
+
`/api/v1/charges`' own mapper treats the same `transaction.value` column
|
|
34
|
+
as decimal reais with no conversion. Corrected to match reality — this is
|
|
35
|
+
a documentation fix, not a behavior or wire-format change.
|
|
36
|
+
- `scheduledCharges.create()`'s docstring claimed the SDK's
|
|
37
|
+
`X-Idempotency-Key` prevents duplicate creates on retry. The gateway does
|
|
38
|
+
not deduplicate `/scheduled-charges` creates against it (same pre-existing
|
|
39
|
+
gap as `webhookEvents.resend()` had). Corrected the docstring; the header
|
|
40
|
+
is still sent (harmless) in case the gateway adds this later.
|
|
41
|
+
|
|
42
|
+
### Migration
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// before (≤ 3.x)
|
|
46
|
+
const { data, meta } = await garu.scheduledCharges.list({ status: 'overdue' });
|
|
47
|
+
meta.total; // number
|
|
48
|
+
|
|
49
|
+
// after (4.0.0)
|
|
50
|
+
const { data, totalCount } = await garu.scheduledCharges.list({ status: 'overdue' });
|
|
51
|
+
totalCount; // number
|
|
52
|
+
```
|
|
53
|
+
|
|
6
54
|
## [3.0.0] — 2026-08-22
|
|
7
55
|
|
|
8
56
|
**Breaking:** `webhookEvents` now targets the versioned public API
|
|
@@ -34,16 +82,16 @@ read the migration below.
|
|
|
34
82
|
// before (0.x – 2.x)
|
|
35
83
|
const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
36
84
|
const event = failed.data[0];
|
|
37
|
-
event.id;
|
|
85
|
+
event.id; // number
|
|
38
86
|
const clone = await garu.webhookEvents.resend(event.id);
|
|
39
|
-
clone.manualResendOf === event.id;
|
|
87
|
+
clone.manualResendOf === event.id; // true
|
|
40
88
|
|
|
41
89
|
// after (3.0.0)
|
|
42
90
|
const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
43
91
|
const event = failed.data[0];
|
|
44
|
-
event.uuid;
|
|
92
|
+
event.uuid; // string
|
|
45
93
|
const clone = await garu.webhookEvents.resend(event.uuid);
|
|
46
|
-
clone.manualResendOf === event.uuid;
|
|
94
|
+
clone.manualResendOf === event.uuid; // true
|
|
47
95
|
```
|
|
48
96
|
|
|
49
97
|
## [2.0.0] — 2026-08-22
|
|
@@ -78,14 +126,14 @@ keyed on `uuid`. If you use `garu.customers.*`, read the migration below.
|
|
|
78
126
|
```ts
|
|
79
127
|
// before (1.x)
|
|
80
128
|
const c = await garu.customers.create({ name, email, document, phone, personType });
|
|
81
|
-
c.id;
|
|
129
|
+
c.id; // number
|
|
82
130
|
const one = await garu.customers.get(c.id);
|
|
83
131
|
await garu.customers.update(c.id, { name: 'Maria Santos' });
|
|
84
132
|
await garu.customers.delete(c.id);
|
|
85
133
|
|
|
86
134
|
// after (2.0.0)
|
|
87
135
|
const c = await garu.customers.create({ name, email, document, phone, personType });
|
|
88
|
-
c.uuid;
|
|
136
|
+
c.uuid; // string
|
|
89
137
|
const one = await garu.customers.get(c.uuid);
|
|
90
138
|
await garu.customers.update(c.uuid, { name: 'Maria Santos' });
|
|
91
139
|
const { removed } = await garu.customers.delete(c.uuid);
|
|
@@ -93,7 +141,6 @@ const { removed } = await garu.customers.delete(c.uuid);
|
|
|
93
141
|
|
|
94
142
|
## [1.1.0] — 2026-08-15
|
|
95
143
|
|
|
96
|
-
|
|
97
144
|
### Added
|
|
98
145
|
|
|
99
146
|
- **`garu.installmentPlans` — boleto parcelado (carnê).** One product sold as N
|
|
@@ -170,22 +217,26 @@ webhook-events) changed.
|
|
|
170
217
|
```ts
|
|
171
218
|
// before (0.16.x)
|
|
172
219
|
const c = await garu.charges.create({
|
|
173
|
-
productId,
|
|
220
|
+
productId,
|
|
221
|
+
paymentMethod: 'credit_card',
|
|
222
|
+
customer,
|
|
174
223
|
cardInfo: { cardNumber: '4111…', cvv, expirationDate, holderName, installments: 2 }
|
|
175
224
|
});
|
|
176
|
-
c.id;
|
|
177
|
-
c.paymentMethodId;
|
|
225
|
+
c.id; // number
|
|
226
|
+
c.paymentMethodId; // 'creditcard'
|
|
178
227
|
const one = await garu.charges.get(c.id);
|
|
179
228
|
await garu.charges.refund(c.id, { amount: 1000 }); // "R$10,00" (bug: reais)
|
|
180
229
|
|
|
181
230
|
// after (1.0.0)
|
|
182
231
|
const c = await garu.charges.create({
|
|
183
|
-
productId,
|
|
232
|
+
productId,
|
|
233
|
+
paymentMethod: 'creditCard',
|
|
234
|
+
customer,
|
|
184
235
|
card: { number: '4111…', cvv, expirationDate, holderName, installments: 2 }
|
|
185
236
|
});
|
|
186
|
-
c.uuid;
|
|
187
|
-
c.paymentMethod;
|
|
188
|
-
c.chargedTotal;
|
|
237
|
+
c.uuid; // string
|
|
238
|
+
c.paymentMethod; // 'creditCard'
|
|
239
|
+
c.chargedTotal; // what was actually charged
|
|
189
240
|
const one = await garu.charges.retrieve(c.uuid);
|
|
190
241
|
await garu.charges.refund(c.uuid, { amount: 10.0 }); // R$10,00
|
|
191
242
|
```
|
package/README.md
CHANGED
|
@@ -147,10 +147,13 @@ await garu.charges.refund('6f1c9b2e-…', { amount: 10.0 }); // partial refund (
|
|
|
147
147
|
## Customers
|
|
148
148
|
|
|
149
149
|
Backed by `/api/v1/customers`, keyed on `uuid` — there is no numeric id in
|
|
150
|
-
this shape. `installmentPlans.create`
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
this shape. `installmentPlans.create` still links customers by the internal
|
|
151
|
+
numeric id (unmigrated resource); fetch that id from the dashboard or the
|
|
152
|
+
internal `/api/customers` endpoint until it moves to `/api/v1` too.
|
|
153
|
+
`scheduledCharges.create` also takes the internal numeric `customerId` —
|
|
154
|
+
customers and scheduled charges are on separate `/api/v1` resources, and
|
|
155
|
+
neither exposes a cross-reference between a customer's `uuid` and their
|
|
156
|
+
numeric id yet.
|
|
154
157
|
|
|
155
158
|
| Method | Description |
|
|
156
159
|
| --------------------------------------- | ----------------------------------------------- |
|
|
@@ -206,20 +209,25 @@ await garu.products.portalConfig.patch('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f', {
|
|
|
206
209
|
|
|
207
210
|
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.
|
|
208
211
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
| `
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
212
|
+
Backed by `/api/v1/scheduled-charges`. Unlike products/customers/webhook-events,
|
|
213
|
+
`id` here was already a stable, non-enumerable string (`sch_...`) before this
|
|
214
|
+
move — there is no separate uuid and no id change, only the path and the list
|
|
215
|
+
envelope (`totalCount`/`totalPages`, not `meta.total`/`meta.totalPages`).
|
|
216
|
+
|
|
217
|
+
| Method | Description |
|
|
218
|
+
| --------------------------------------- | ------------------------------------------------------------------------- |
|
|
219
|
+
| `create(params)` | Create one-time or recurring schedule. |
|
|
220
|
+
| `list(params?)` | Paginated list with status / type / dueFrom / dueTo / customerId filters. |
|
|
221
|
+
| `get(id)` | Detail bundle: charge + event timeline + linked transactions. |
|
|
222
|
+
| `chargeNow(id)` | Force-bill the current cycle now instead of waiting for the due date. |
|
|
223
|
+
| `markPaid(id, params)` | Mark cycle paid (off-Garu reconciliation). |
|
|
224
|
+
| `postpone(id, params)` | Move the next cycle's due date forward. |
|
|
225
|
+
| `pause(id, params?)` / `resume(id)` | Suspend / re-enable a series. |
|
|
226
|
+
| `cancelRecurrence(id, params?)` | Hard-stop future cycles (recurring only). |
|
|
227
|
+
| `setCancelAtPeriodEnd(id, { enabled })` | Stripe-style soft-cancel; reversible. |
|
|
228
|
+
| `changePaymentMethod(id, params)` | Swap the saved card. |
|
|
229
|
+
| `clearPaymentMethod(id)` | Remove the saved card; future cycles email-with-link. |
|
|
230
|
+
| `listAttempts(id, params?)` | Per-attempt billing log — every silent-charge / retry / mark-paid. |
|
|
223
231
|
|
|
224
232
|
```ts
|
|
225
233
|
// Recurring with 7-day trial. `maxRecoveryDays` caps how long past the due
|
|
@@ -240,11 +248,10 @@ const series = await garu.scheduledCharges.create({
|
|
|
240
248
|
// Idempotent: a cycle already dispatched today reports `already_sent`.
|
|
241
249
|
const result = await garu.scheduledCharges.chargeNow(series.id);
|
|
242
250
|
if (result.outcome === 'failed') {
|
|
243
|
-
|
|
244
|
-
console.error(`${result.message} (${result.reason})`);
|
|
251
|
+
result.reason; // e.g. 'card_expired' or a gateway decline code
|
|
245
252
|
}
|
|
246
253
|
|
|
247
|
-
// Audit why cycle 3 failed
|
|
254
|
+
// Audit why cycle 3 failed
|
|
248
255
|
const { data } = await garu.scheduledCharges.listAttempts(series.id, {
|
|
249
256
|
cycleNumber: 3
|
|
250
257
|
});
|
|
@@ -308,7 +315,7 @@ const series = await garu.scheduledCharges.create({
|
|
|
308
315
|
});
|
|
309
316
|
```
|
|
310
317
|
|
|
311
|
-
Cancel and the rest of the lifecycle use the **same methods** as card-backed series — `cancelRecurrence(id)`, `
|
|
318
|
+
Cancel and the rest of the lifecycle use the **same methods** as card-backed series — `cancelRecurrence(id)`, `setCancelAtPeriodEnd(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.
|
|
312
319
|
|
|
313
320
|
### 3. Handle the webhooks
|
|
314
321
|
|
package/dist/index.cjs
CHANGED
|
@@ -942,9 +942,13 @@ var ScheduledCharges = class {
|
|
|
942
942
|
}
|
|
943
943
|
http;
|
|
944
944
|
/**
|
|
945
|
-
* Create a new scheduled charge.
|
|
946
|
-
* (UUIDv4
|
|
947
|
-
*
|
|
945
|
+
* Create a new scheduled charge. The SDK attaches an `X-Idempotency-Key`
|
|
946
|
+
* header (UUIDv4 unless you pass `idempotencyKey`), but the gateway does
|
|
947
|
+
* not currently deduplicate `/scheduled-charges` creates against it — a
|
|
948
|
+
* retry after a network failure can create more than one series. Pair
|
|
949
|
+
* this with your own retry-suppression (e.g. check `list` for an existing
|
|
950
|
+
* series with the same `externalReference`) if that matters for your
|
|
951
|
+
* integration.
|
|
948
952
|
*
|
|
949
953
|
* @example
|
|
950
954
|
* const charge = await garu.scheduledCharges.create({
|
|
@@ -974,7 +978,7 @@ var ScheduledCharges = class {
|
|
|
974
978
|
const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
|
|
975
979
|
const { idempotencyKey: _omit, ...body } = params;
|
|
976
980
|
return this.http.call(
|
|
977
|
-
(signal) => this.http.client.POST("/api/scheduled-charges", {
|
|
981
|
+
(signal) => this.http.client.POST("/api/v1/scheduled-charges", {
|
|
978
982
|
body,
|
|
979
983
|
headers: { "X-Idempotency-Key": idempotencyKey },
|
|
980
984
|
signal
|
|
@@ -1009,7 +1013,7 @@ var ScheduledCharges = class {
|
|
|
1009
1013
|
for (const s of statuses) qs.append("status", s);
|
|
1010
1014
|
}
|
|
1011
1015
|
const query = qs.toString();
|
|
1012
|
-
const url = `/api/scheduled-charges${query ? `?${query}` : ""}`;
|
|
1016
|
+
const url = `/api/v1/scheduled-charges${query ? `?${query}` : ""}`;
|
|
1013
1017
|
return this.http.call(
|
|
1014
1018
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1015
1019
|
(r) => r
|
|
@@ -1026,7 +1030,7 @@ var ScheduledCharges = class {
|
|
|
1026
1030
|
*/
|
|
1027
1031
|
async get(id) {
|
|
1028
1032
|
return this.http.call(
|
|
1029
|
-
(signal) => this.http.client.GET(`/api/scheduled-charges/${encodeURIComponent(id)}`, {
|
|
1033
|
+
(signal) => this.http.client.GET(`/api/v1/scheduled-charges/${encodeURIComponent(id)}`, {
|
|
1030
1034
|
signal
|
|
1031
1035
|
}).then((r) => r)
|
|
1032
1036
|
);
|
|
@@ -1045,7 +1049,7 @@ var ScheduledCharges = class {
|
|
|
1045
1049
|
async postpone(id, params) {
|
|
1046
1050
|
return this.http.call(
|
|
1047
1051
|
(signal) => this.http.client.POST(
|
|
1048
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/postpone`,
|
|
1052
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/postpone`,
|
|
1049
1053
|
{
|
|
1050
1054
|
body: params,
|
|
1051
1055
|
signal
|
|
@@ -1064,7 +1068,7 @@ var ScheduledCharges = class {
|
|
|
1064
1068
|
async pause(id, params = {}) {
|
|
1065
1069
|
return this.http.call(
|
|
1066
1070
|
(signal) => this.http.client.POST(
|
|
1067
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/pause`,
|
|
1071
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/pause`,
|
|
1068
1072
|
{
|
|
1069
1073
|
body: params,
|
|
1070
1074
|
signal
|
|
@@ -1081,7 +1085,7 @@ var ScheduledCharges = class {
|
|
|
1081
1085
|
async resume(id) {
|
|
1082
1086
|
return this.http.call(
|
|
1083
1087
|
(signal) => this.http.client.POST(
|
|
1084
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/resume`,
|
|
1088
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/resume`,
|
|
1085
1089
|
{
|
|
1086
1090
|
body: {},
|
|
1087
1091
|
signal
|
|
@@ -1115,7 +1119,7 @@ var ScheduledCharges = class {
|
|
|
1115
1119
|
async markPaid(id, params) {
|
|
1116
1120
|
return this.http.call(
|
|
1117
1121
|
(signal) => this.http.client.POST(
|
|
1118
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
|
|
1122
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
|
|
1119
1123
|
{
|
|
1120
1124
|
body: params,
|
|
1121
1125
|
signal
|
|
@@ -1137,24 +1141,22 @@ var ScheduledCharges = class {
|
|
|
1137
1141
|
* const result = await garu.scheduledCharges.chargeNow('sch_abc123');
|
|
1138
1142
|
* switch (result.outcome) {
|
|
1139
1143
|
* case 'dispatched':
|
|
1140
|
-
*
|
|
1144
|
+
* result.cycleNumber; // billed this cycle
|
|
1141
1145
|
* break;
|
|
1142
1146
|
* case 'already_sent':
|
|
1143
|
-
*
|
|
1144
|
-
* break;
|
|
1147
|
+
* break; // nothing to do
|
|
1145
1148
|
* case 'failed':
|
|
1146
|
-
*
|
|
1147
|
-
* console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
|
|
1149
|
+
* result.reason; // e.g. 'card_expired' or a gateway decline code
|
|
1148
1150
|
* break;
|
|
1149
1151
|
* case 'not_sent':
|
|
1150
|
-
*
|
|
1152
|
+
* result.reason;
|
|
1151
1153
|
* break;
|
|
1152
1154
|
* }
|
|
1153
1155
|
*/
|
|
1154
1156
|
async chargeNow(id) {
|
|
1155
1157
|
return this.http.call(
|
|
1156
1158
|
(signal) => this.http.client.POST(
|
|
1157
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
|
|
1159
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
|
|
1158
1160
|
{
|
|
1159
1161
|
body: {},
|
|
1160
1162
|
signal
|
|
@@ -1176,7 +1178,7 @@ var ScheduledCharges = class {
|
|
|
1176
1178
|
async cancelRecurrence(id, params = {}) {
|
|
1177
1179
|
return this.http.call(
|
|
1178
1180
|
(signal) => this.http.client.POST(
|
|
1179
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
|
|
1181
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
|
|
1180
1182
|
{
|
|
1181
1183
|
body: params,
|
|
1182
1184
|
signal
|
|
@@ -1196,7 +1198,7 @@ var ScheduledCharges = class {
|
|
|
1196
1198
|
async setCancelAtPeriodEnd(id, params) {
|
|
1197
1199
|
return this.http.call(
|
|
1198
1200
|
(signal) => this.http.client.POST(
|
|
1199
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
|
|
1201
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
|
|
1200
1202
|
{
|
|
1201
1203
|
body: params,
|
|
1202
1204
|
signal
|
|
@@ -1215,7 +1217,7 @@ var ScheduledCharges = class {
|
|
|
1215
1217
|
async changePaymentMethod(id, params) {
|
|
1216
1218
|
return this.http.call(
|
|
1217
1219
|
(signal) => this.http.client.POST(
|
|
1218
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1220
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1219
1221
|
{
|
|
1220
1222
|
body: params,
|
|
1221
1223
|
signal
|
|
@@ -1234,7 +1236,7 @@ var ScheduledCharges = class {
|
|
|
1234
1236
|
async clearPaymentMethod(id) {
|
|
1235
1237
|
return this.http.call(
|
|
1236
1238
|
(signal) => this.http.client.DELETE(
|
|
1237
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1239
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1238
1240
|
{
|
|
1239
1241
|
body: {},
|
|
1240
1242
|
signal
|
|
@@ -1261,7 +1263,7 @@ var ScheduledCharges = class {
|
|
|
1261
1263
|
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
1262
1264
|
if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
|
|
1263
1265
|
const query = qs.toString();
|
|
1264
|
-
const url = `/api/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
|
|
1266
|
+
const url = `/api/v1/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
|
|
1265
1267
|
return this.http.call(
|
|
1266
1268
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1267
1269
|
(r) => r
|
package/dist/index.d.cts
CHANGED
|
@@ -390,7 +390,13 @@ interface ScheduledChargeRecord {
|
|
|
390
390
|
/** YYYY-MM-DD in São Paulo time. */
|
|
391
391
|
dueDate: string;
|
|
392
392
|
methods: ScheduledPaymentMethod[];
|
|
393
|
+
recurrence: RecurrenceConfig | null;
|
|
393
394
|
status: ScheduledChargeStatus;
|
|
395
|
+
subscriptionId: number | null;
|
|
396
|
+
/** ISO-8601. Set only when the series was created with `trialDays`. */
|
|
397
|
+
trialEndsAt: string | null;
|
|
398
|
+
/** Recurring only. Toggle with `setCancelAtPeriodEnd`. */
|
|
399
|
+
cancelAtPeriodEnd: boolean;
|
|
394
400
|
externalReference: string | null;
|
|
395
401
|
/**
|
|
396
402
|
* Max days past `dueDate` the daily recovery sweep will still auto-bill a
|
|
@@ -425,7 +431,7 @@ interface ScheduledChargeEvent {
|
|
|
425
431
|
}
|
|
426
432
|
interface ScheduledChargeLinkedTransaction {
|
|
427
433
|
id: number;
|
|
428
|
-
/**
|
|
434
|
+
/** Decimal BRL (e.g. `297.50`), never centavos. */
|
|
429
435
|
value: number;
|
|
430
436
|
paymentMethod: string;
|
|
431
437
|
status: string;
|
|
@@ -438,7 +444,14 @@ interface ScheduledChargeDetail {
|
|
|
438
444
|
events: ScheduledChargeEvent[];
|
|
439
445
|
transactions: ScheduledChargeLinkedTransaction[];
|
|
440
446
|
}
|
|
441
|
-
|
|
447
|
+
interface ScheduledChargeList {
|
|
448
|
+
data: ScheduledChargeRecord[];
|
|
449
|
+
/** Items on this page. */
|
|
450
|
+
count: number;
|
|
451
|
+
/** Total matches across all pages. */
|
|
452
|
+
totalCount: number;
|
|
453
|
+
totalPages: number;
|
|
454
|
+
}
|
|
442
455
|
/** Source of a billing attempt — see SPEC §3.1. */
|
|
443
456
|
type ScheduledChargeAttemptSource = 'cycle1_interactive' | 'silent_charge' | 'card_retry' | 'manual_mark_paid' | 'fallback_pix';
|
|
444
457
|
type ScheduledChargeAttemptStatus = 'pending' | 'succeeded' | 'declined' | 'canceled' | 'errored';
|
|
@@ -460,7 +473,14 @@ interface ScheduledChargeAttempt {
|
|
|
460
473
|
gatewayChargeId: number | null;
|
|
461
474
|
transactionId: number | null;
|
|
462
475
|
}
|
|
463
|
-
|
|
476
|
+
interface ScheduledChargeAttemptList {
|
|
477
|
+
data: ScheduledChargeAttempt[];
|
|
478
|
+
/** Items on this page. */
|
|
479
|
+
count: number;
|
|
480
|
+
/** Total matches across all pages. */
|
|
481
|
+
totalCount: number;
|
|
482
|
+
totalPages: number;
|
|
483
|
+
}
|
|
464
484
|
interface ListScheduledChargeAttemptsParams {
|
|
465
485
|
page?: number;
|
|
466
486
|
limit?: number;
|
|
@@ -1573,9 +1593,13 @@ declare class ScheduledCharges {
|
|
|
1573
1593
|
private readonly http;
|
|
1574
1594
|
constructor(http: HttpClient);
|
|
1575
1595
|
/**
|
|
1576
|
-
* Create a new scheduled charge.
|
|
1577
|
-
* (UUIDv4
|
|
1578
|
-
*
|
|
1596
|
+
* Create a new scheduled charge. The SDK attaches an `X-Idempotency-Key`
|
|
1597
|
+
* header (UUIDv4 unless you pass `idempotencyKey`), but the gateway does
|
|
1598
|
+
* not currently deduplicate `/scheduled-charges` creates against it — a
|
|
1599
|
+
* retry after a network failure can create more than one series. Pair
|
|
1600
|
+
* this with your own retry-suppression (e.g. check `list` for an existing
|
|
1601
|
+
* series with the same `externalReference`) if that matters for your
|
|
1602
|
+
* integration.
|
|
1579
1603
|
*
|
|
1580
1604
|
* @example
|
|
1581
1605
|
* const charge = await garu.scheduledCharges.create({
|
|
@@ -1692,17 +1716,15 @@ declare class ScheduledCharges {
|
|
|
1692
1716
|
* const result = await garu.scheduledCharges.chargeNow('sch_abc123');
|
|
1693
1717
|
* switch (result.outcome) {
|
|
1694
1718
|
* case 'dispatched':
|
|
1695
|
-
*
|
|
1719
|
+
* result.cycleNumber; // billed this cycle
|
|
1696
1720
|
* break;
|
|
1697
1721
|
* case 'already_sent':
|
|
1698
|
-
*
|
|
1699
|
-
* break;
|
|
1722
|
+
* break; // nothing to do
|
|
1700
1723
|
* case 'failed':
|
|
1701
|
-
*
|
|
1702
|
-
* console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
|
|
1724
|
+
* result.reason; // e.g. 'card_expired' or a gateway decline code
|
|
1703
1725
|
* break;
|
|
1704
1726
|
* case 'not_sent':
|
|
1705
|
-
*
|
|
1727
|
+
* result.reason;
|
|
1706
1728
|
* break;
|
|
1707
1729
|
* }
|
|
1708
1730
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -390,7 +390,13 @@ interface ScheduledChargeRecord {
|
|
|
390
390
|
/** YYYY-MM-DD in São Paulo time. */
|
|
391
391
|
dueDate: string;
|
|
392
392
|
methods: ScheduledPaymentMethod[];
|
|
393
|
+
recurrence: RecurrenceConfig | null;
|
|
393
394
|
status: ScheduledChargeStatus;
|
|
395
|
+
subscriptionId: number | null;
|
|
396
|
+
/** ISO-8601. Set only when the series was created with `trialDays`. */
|
|
397
|
+
trialEndsAt: string | null;
|
|
398
|
+
/** Recurring only. Toggle with `setCancelAtPeriodEnd`. */
|
|
399
|
+
cancelAtPeriodEnd: boolean;
|
|
394
400
|
externalReference: string | null;
|
|
395
401
|
/**
|
|
396
402
|
* Max days past `dueDate` the daily recovery sweep will still auto-bill a
|
|
@@ -425,7 +431,7 @@ interface ScheduledChargeEvent {
|
|
|
425
431
|
}
|
|
426
432
|
interface ScheduledChargeLinkedTransaction {
|
|
427
433
|
id: number;
|
|
428
|
-
/**
|
|
434
|
+
/** Decimal BRL (e.g. `297.50`), never centavos. */
|
|
429
435
|
value: number;
|
|
430
436
|
paymentMethod: string;
|
|
431
437
|
status: string;
|
|
@@ -438,7 +444,14 @@ interface ScheduledChargeDetail {
|
|
|
438
444
|
events: ScheduledChargeEvent[];
|
|
439
445
|
transactions: ScheduledChargeLinkedTransaction[];
|
|
440
446
|
}
|
|
441
|
-
|
|
447
|
+
interface ScheduledChargeList {
|
|
448
|
+
data: ScheduledChargeRecord[];
|
|
449
|
+
/** Items on this page. */
|
|
450
|
+
count: number;
|
|
451
|
+
/** Total matches across all pages. */
|
|
452
|
+
totalCount: number;
|
|
453
|
+
totalPages: number;
|
|
454
|
+
}
|
|
442
455
|
/** Source of a billing attempt — see SPEC §3.1. */
|
|
443
456
|
type ScheduledChargeAttemptSource = 'cycle1_interactive' | 'silent_charge' | 'card_retry' | 'manual_mark_paid' | 'fallback_pix';
|
|
444
457
|
type ScheduledChargeAttemptStatus = 'pending' | 'succeeded' | 'declined' | 'canceled' | 'errored';
|
|
@@ -460,7 +473,14 @@ interface ScheduledChargeAttempt {
|
|
|
460
473
|
gatewayChargeId: number | null;
|
|
461
474
|
transactionId: number | null;
|
|
462
475
|
}
|
|
463
|
-
|
|
476
|
+
interface ScheduledChargeAttemptList {
|
|
477
|
+
data: ScheduledChargeAttempt[];
|
|
478
|
+
/** Items on this page. */
|
|
479
|
+
count: number;
|
|
480
|
+
/** Total matches across all pages. */
|
|
481
|
+
totalCount: number;
|
|
482
|
+
totalPages: number;
|
|
483
|
+
}
|
|
464
484
|
interface ListScheduledChargeAttemptsParams {
|
|
465
485
|
page?: number;
|
|
466
486
|
limit?: number;
|
|
@@ -1573,9 +1593,13 @@ declare class ScheduledCharges {
|
|
|
1573
1593
|
private readonly http;
|
|
1574
1594
|
constructor(http: HttpClient);
|
|
1575
1595
|
/**
|
|
1576
|
-
* Create a new scheduled charge.
|
|
1577
|
-
* (UUIDv4
|
|
1578
|
-
*
|
|
1596
|
+
* Create a new scheduled charge. The SDK attaches an `X-Idempotency-Key`
|
|
1597
|
+
* header (UUIDv4 unless you pass `idempotencyKey`), but the gateway does
|
|
1598
|
+
* not currently deduplicate `/scheduled-charges` creates against it — a
|
|
1599
|
+
* retry after a network failure can create more than one series. Pair
|
|
1600
|
+
* this with your own retry-suppression (e.g. check `list` for an existing
|
|
1601
|
+
* series with the same `externalReference`) if that matters for your
|
|
1602
|
+
* integration.
|
|
1579
1603
|
*
|
|
1580
1604
|
* @example
|
|
1581
1605
|
* const charge = await garu.scheduledCharges.create({
|
|
@@ -1692,17 +1716,15 @@ declare class ScheduledCharges {
|
|
|
1692
1716
|
* const result = await garu.scheduledCharges.chargeNow('sch_abc123');
|
|
1693
1717
|
* switch (result.outcome) {
|
|
1694
1718
|
* case 'dispatched':
|
|
1695
|
-
*
|
|
1719
|
+
* result.cycleNumber; // billed this cycle
|
|
1696
1720
|
* break;
|
|
1697
1721
|
* case 'already_sent':
|
|
1698
|
-
*
|
|
1699
|
-
* break;
|
|
1722
|
+
* break; // nothing to do
|
|
1700
1723
|
* case 'failed':
|
|
1701
|
-
*
|
|
1702
|
-
* console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
|
|
1724
|
+
* result.reason; // e.g. 'card_expired' or a gateway decline code
|
|
1703
1725
|
* break;
|
|
1704
1726
|
* case 'not_sent':
|
|
1705
|
-
*
|
|
1727
|
+
* result.reason;
|
|
1706
1728
|
* break;
|
|
1707
1729
|
* }
|
|
1708
1730
|
*/
|
package/dist/index.js
CHANGED
|
@@ -936,9 +936,13 @@ var ScheduledCharges = class {
|
|
|
936
936
|
}
|
|
937
937
|
http;
|
|
938
938
|
/**
|
|
939
|
-
* Create a new scheduled charge.
|
|
940
|
-
* (UUIDv4
|
|
941
|
-
*
|
|
939
|
+
* Create a new scheduled charge. The SDK attaches an `X-Idempotency-Key`
|
|
940
|
+
* header (UUIDv4 unless you pass `idempotencyKey`), but the gateway does
|
|
941
|
+
* not currently deduplicate `/scheduled-charges` creates against it — a
|
|
942
|
+
* retry after a network failure can create more than one series. Pair
|
|
943
|
+
* this with your own retry-suppression (e.g. check `list` for an existing
|
|
944
|
+
* series with the same `externalReference`) if that matters for your
|
|
945
|
+
* integration.
|
|
942
946
|
*
|
|
943
947
|
* @example
|
|
944
948
|
* const charge = await garu.scheduledCharges.create({
|
|
@@ -968,7 +972,7 @@ var ScheduledCharges = class {
|
|
|
968
972
|
const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
|
|
969
973
|
const { idempotencyKey: _omit, ...body } = params;
|
|
970
974
|
return this.http.call(
|
|
971
|
-
(signal) => this.http.client.POST("/api/scheduled-charges", {
|
|
975
|
+
(signal) => this.http.client.POST("/api/v1/scheduled-charges", {
|
|
972
976
|
body,
|
|
973
977
|
headers: { "X-Idempotency-Key": idempotencyKey },
|
|
974
978
|
signal
|
|
@@ -1003,7 +1007,7 @@ var ScheduledCharges = class {
|
|
|
1003
1007
|
for (const s of statuses) qs.append("status", s);
|
|
1004
1008
|
}
|
|
1005
1009
|
const query = qs.toString();
|
|
1006
|
-
const url = `/api/scheduled-charges${query ? `?${query}` : ""}`;
|
|
1010
|
+
const url = `/api/v1/scheduled-charges${query ? `?${query}` : ""}`;
|
|
1007
1011
|
return this.http.call(
|
|
1008
1012
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1009
1013
|
(r) => r
|
|
@@ -1020,7 +1024,7 @@ var ScheduledCharges = class {
|
|
|
1020
1024
|
*/
|
|
1021
1025
|
async get(id) {
|
|
1022
1026
|
return this.http.call(
|
|
1023
|
-
(signal) => this.http.client.GET(`/api/scheduled-charges/${encodeURIComponent(id)}`, {
|
|
1027
|
+
(signal) => this.http.client.GET(`/api/v1/scheduled-charges/${encodeURIComponent(id)}`, {
|
|
1024
1028
|
signal
|
|
1025
1029
|
}).then((r) => r)
|
|
1026
1030
|
);
|
|
@@ -1039,7 +1043,7 @@ var ScheduledCharges = class {
|
|
|
1039
1043
|
async postpone(id, params) {
|
|
1040
1044
|
return this.http.call(
|
|
1041
1045
|
(signal) => this.http.client.POST(
|
|
1042
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/postpone`,
|
|
1046
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/postpone`,
|
|
1043
1047
|
{
|
|
1044
1048
|
body: params,
|
|
1045
1049
|
signal
|
|
@@ -1058,7 +1062,7 @@ var ScheduledCharges = class {
|
|
|
1058
1062
|
async pause(id, params = {}) {
|
|
1059
1063
|
return this.http.call(
|
|
1060
1064
|
(signal) => this.http.client.POST(
|
|
1061
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/pause`,
|
|
1065
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/pause`,
|
|
1062
1066
|
{
|
|
1063
1067
|
body: params,
|
|
1064
1068
|
signal
|
|
@@ -1075,7 +1079,7 @@ var ScheduledCharges = class {
|
|
|
1075
1079
|
async resume(id) {
|
|
1076
1080
|
return this.http.call(
|
|
1077
1081
|
(signal) => this.http.client.POST(
|
|
1078
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/resume`,
|
|
1082
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/resume`,
|
|
1079
1083
|
{
|
|
1080
1084
|
body: {},
|
|
1081
1085
|
signal
|
|
@@ -1109,7 +1113,7 @@ var ScheduledCharges = class {
|
|
|
1109
1113
|
async markPaid(id, params) {
|
|
1110
1114
|
return this.http.call(
|
|
1111
1115
|
(signal) => this.http.client.POST(
|
|
1112
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
|
|
1116
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/mark-paid`,
|
|
1113
1117
|
{
|
|
1114
1118
|
body: params,
|
|
1115
1119
|
signal
|
|
@@ -1131,24 +1135,22 @@ var ScheduledCharges = class {
|
|
|
1131
1135
|
* const result = await garu.scheduledCharges.chargeNow('sch_abc123');
|
|
1132
1136
|
* switch (result.outcome) {
|
|
1133
1137
|
* case 'dispatched':
|
|
1134
|
-
*
|
|
1138
|
+
* result.cycleNumber; // billed this cycle
|
|
1135
1139
|
* break;
|
|
1136
1140
|
* case 'already_sent':
|
|
1137
|
-
*
|
|
1138
|
-
* break;
|
|
1141
|
+
* break; // nothing to do
|
|
1139
1142
|
* case 'failed':
|
|
1140
|
-
*
|
|
1141
|
-
* console.error(`Falha na cobrança: ${result.reason}. ${result.message}`);
|
|
1143
|
+
* result.reason; // e.g. 'card_expired' or a gateway decline code
|
|
1142
1144
|
* break;
|
|
1143
1145
|
* case 'not_sent':
|
|
1144
|
-
*
|
|
1146
|
+
* result.reason;
|
|
1145
1147
|
* break;
|
|
1146
1148
|
* }
|
|
1147
1149
|
*/
|
|
1148
1150
|
async chargeNow(id) {
|
|
1149
1151
|
return this.http.call(
|
|
1150
1152
|
(signal) => this.http.client.POST(
|
|
1151
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
|
|
1153
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/charge-now`,
|
|
1152
1154
|
{
|
|
1153
1155
|
body: {},
|
|
1154
1156
|
signal
|
|
@@ -1170,7 +1172,7 @@ var ScheduledCharges = class {
|
|
|
1170
1172
|
async cancelRecurrence(id, params = {}) {
|
|
1171
1173
|
return this.http.call(
|
|
1172
1174
|
(signal) => this.http.client.POST(
|
|
1173
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
|
|
1175
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/cancel-recurrence`,
|
|
1174
1176
|
{
|
|
1175
1177
|
body: params,
|
|
1176
1178
|
signal
|
|
@@ -1190,7 +1192,7 @@ var ScheduledCharges = class {
|
|
|
1190
1192
|
async setCancelAtPeriodEnd(id, params) {
|
|
1191
1193
|
return this.http.call(
|
|
1192
1194
|
(signal) => this.http.client.POST(
|
|
1193
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
|
|
1195
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/cancel-at-period-end`,
|
|
1194
1196
|
{
|
|
1195
1197
|
body: params,
|
|
1196
1198
|
signal
|
|
@@ -1209,7 +1211,7 @@ var ScheduledCharges = class {
|
|
|
1209
1211
|
async changePaymentMethod(id, params) {
|
|
1210
1212
|
return this.http.call(
|
|
1211
1213
|
(signal) => this.http.client.POST(
|
|
1212
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1214
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1213
1215
|
{
|
|
1214
1216
|
body: params,
|
|
1215
1217
|
signal
|
|
@@ -1228,7 +1230,7 @@ var ScheduledCharges = class {
|
|
|
1228
1230
|
async clearPaymentMethod(id) {
|
|
1229
1231
|
return this.http.call(
|
|
1230
1232
|
(signal) => this.http.client.DELETE(
|
|
1231
|
-
`/api/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1233
|
+
`/api/v1/scheduled-charges/${encodeURIComponent(id)}/payment-method`,
|
|
1232
1234
|
{
|
|
1233
1235
|
body: {},
|
|
1234
1236
|
signal
|
|
@@ -1255,7 +1257,7 @@ var ScheduledCharges = class {
|
|
|
1255
1257
|
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
1256
1258
|
if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
|
|
1257
1259
|
const query = qs.toString();
|
|
1258
|
-
const url = `/api/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
|
|
1260
|
+
const url = `/api/v1/scheduled-charges/${encodeURIComponent(id)}/attempts${query ? `?${query}` : ""}`;
|
|
1259
1261
|
return this.http.call(
|
|
1260
1262
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1261
1263
|
(r) => r
|