@garuhq/node 0.6.0 → 0.8.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/README.md +84 -0
- package/dist/index.cjs +95 -0
- package/dist/index.d.cts +183 -2
- package/dist/index.d.ts +183 -2
- package/dist/index.js +95 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -165,6 +165,90 @@ const customer = await garu.customers.create({
|
|
|
165
165
|
const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
+
## Products
|
|
169
|
+
|
|
170
|
+
Discover products and customize the per-product portal experience (B2B2C, v0.8.0).
|
|
171
|
+
|
|
172
|
+
| Method | Description |
|
|
173
|
+
| ----------------------------------- | ----------------------------------------------------------------- |
|
|
174
|
+
| `list(params?)` | Paginated list of products for the seller. |
|
|
175
|
+
| `get(uuid)` | Fetch a single product by UUID — same id used by charges. |
|
|
176
|
+
| `portalConfig.get(productId)` | Read per-product portal customization. Returns `null` if unset. |
|
|
177
|
+
| `portalConfig.set(productId, p)` | Upsert with merge — only fields present are written. |
|
|
178
|
+
| `portalConfig.patch(productId, p)` | Same merge semantics as `set` — alias for HTTP-PATCH callers. |
|
|
179
|
+
| `portalConfig.clear(productId)` | Remove the customization; product falls back to seller config. |
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
// SaaS de coaching: per-coach branding under one Seller account
|
|
183
|
+
await garu.products.portalConfig.set(57, {
|
|
184
|
+
businessName: 'Coach Maria — Corrida & Trilha',
|
|
185
|
+
primaryColor: '#257264',
|
|
186
|
+
logoUrl: 'https://cdn.exemplo.com/coaches/maria.png',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Pass `null` on a field to inherit from the seller-level config
|
|
190
|
+
await garu.products.portalConfig.patch(57, { primaryColor: null });
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Scheduled charges
|
|
194
|
+
|
|
195
|
+
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.
|
|
196
|
+
|
|
197
|
+
| Method | Description |
|
|
198
|
+
| --------------------------------------------- | -------------------------------------------------------------------------- |
|
|
199
|
+
| `create(params)` | Create one-time or recurring schedule. Auto-attaches `X-Idempotency-Key`. |
|
|
200
|
+
| `list(params?)` | Paginated list with status / type / dueFrom / dueTo / customerId filters. |
|
|
201
|
+
| `get(id)` | Detail bundle: charge + event timeline + linked transactions. |
|
|
202
|
+
| `markPaid(id, params)` | Mark cycle paid (off-Garu reconciliation). |
|
|
203
|
+
| `postpone(id, params)` | Move the next cycle's due date forward. |
|
|
204
|
+
| `pause(id, params?)` / `resume(id)` | Suspend / re-enable a series. |
|
|
205
|
+
| `cancelRecurrence(id, params?)` | Hard-stop future cycles (recurring only). |
|
|
206
|
+
| `cancelAtPeriodEnd(id, { enabled })` | Stripe-style soft-cancel; reversible. |
|
|
207
|
+
| `changePaymentMethod(id, params)` | Swap the saved card. |
|
|
208
|
+
| `clearPaymentMethod(id)` | Remove the saved card; future cycles email-with-link. |
|
|
209
|
+
| `listAttempts(id, params?)` | Per-attempt billing log — every silent-charge / retry / mark-paid (v0.8.2).|
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// Recurring with 7-day trial
|
|
213
|
+
const series = await garu.scheduledCharges.create({
|
|
214
|
+
customerId: 42,
|
|
215
|
+
productId: 17,
|
|
216
|
+
amount: 49.9,
|
|
217
|
+
type: 'recurring',
|
|
218
|
+
dueDate: '2026-06-01',
|
|
219
|
+
methods: ['card', 'pix'],
|
|
220
|
+
recurrence: { interval: 'monthly' },
|
|
221
|
+
trialDays: 7,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Audit why cycle 3 failed (v0.8.2)
|
|
225
|
+
const { data } = await garu.scheduledCharges.listAttempts(series.id, {
|
|
226
|
+
cycleNumber: 3,
|
|
227
|
+
});
|
|
228
|
+
const declines = data.filter((a) => a.status === 'declined');
|
|
229
|
+
// → each declines[i].failureCode is one of GaruFailureCode (insufficient_funds,
|
|
230
|
+
// card_expired, card_declined, ...)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Failure codes (v0.8.0)
|
|
234
|
+
|
|
235
|
+
Every `transaction.payment.failed`, `scheduled_charge.cycle_failed`, and `listAttempts()` row carries:
|
|
236
|
+
|
|
237
|
+
- `failureCode` — canonical `GaruFailureCode` enum (10 values, gateway-independent)
|
|
238
|
+
- `failureReason` — human-readable PT-BR
|
|
239
|
+
- `gatewayFailureCode` — raw code from Celcoin (ABECS for forensics)
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import type { GaruFailureCode } from '@garuhq/node';
|
|
243
|
+
|
|
244
|
+
const PERMANENT: GaruFailureCode[] = ['card_expired', 'card_canceled', 'fraud_suspected'];
|
|
245
|
+
function shouldAskForNewCard(code: GaruFailureCode): boolean {
|
|
246
|
+
return PERMANENT.includes(code);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Full table at [docs.garu.com.br/api-reference/webhooks/codigos-de-falha](https://docs.garu.com.br/api-reference/webhooks/codigos-de-falha).
|
|
251
|
+
|
|
168
252
|
## Meta
|
|
169
253
|
|
|
170
254
|
Discover available payment methods and webhook events. No authentication required.
|
package/dist/index.cjs
CHANGED
|
@@ -464,11 +464,80 @@ var Meta = class {
|
|
|
464
464
|
};
|
|
465
465
|
|
|
466
466
|
// src/resources/products.ts
|
|
467
|
+
var ProductPortalConfigResource = class {
|
|
468
|
+
constructor(http) {
|
|
469
|
+
this.http = http;
|
|
470
|
+
}
|
|
471
|
+
http;
|
|
472
|
+
/**
|
|
473
|
+
* Get the portal customization for a product. Returns `null` when no
|
|
474
|
+
* per-product config exists (the product falls back to seller-level
|
|
475
|
+
* portal config).
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* const cfg = await garu.products.portalConfig.get(57);
|
|
479
|
+
*/
|
|
480
|
+
async get(productId) {
|
|
481
|
+
return this.http.call(
|
|
482
|
+
(signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
|
|
483
|
+
signal
|
|
484
|
+
}).then((r) => r)
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Create or merge the portal customization (idempotent upsert). Both
|
|
489
|
+
* `set` and `patch` have the same merge semantics — only fields present
|
|
490
|
+
* in the body are written, unspecified fields keep their persisted
|
|
491
|
+
* value. Use `clear` to reset everything.
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* await garu.products.portalConfig.set(57, {
|
|
495
|
+
* businessName: 'Coach Maria — Corrida & Trilha',
|
|
496
|
+
* primaryColor: '#257264',
|
|
497
|
+
* logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
|
|
498
|
+
* });
|
|
499
|
+
*/
|
|
500
|
+
async set(productId, params) {
|
|
501
|
+
return this.http.call(
|
|
502
|
+
(signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
|
|
503
|
+
body: params,
|
|
504
|
+
signal
|
|
505
|
+
}).then((r) => r)
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
/** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
|
|
509
|
+
async patch(productId, params) {
|
|
510
|
+
return this.http.call(
|
|
511
|
+
(signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
|
|
512
|
+
body: params,
|
|
513
|
+
signal
|
|
514
|
+
}).then((r) => r)
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Remove the per-product config. The product falls back to the
|
|
519
|
+
* seller-level portal config. Returns `{ removed: true }` when a row was
|
|
520
|
+
* deleted, `{ removed: false }` when there was nothing to remove.
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* await garu.products.portalConfig.clear(57);
|
|
524
|
+
*/
|
|
525
|
+
async clear(productId) {
|
|
526
|
+
return this.http.call(
|
|
527
|
+
(signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
|
|
528
|
+
signal
|
|
529
|
+
}).then((r) => r)
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
467
533
|
var Products = class {
|
|
468
534
|
constructor(http) {
|
|
469
535
|
this.http = http;
|
|
536
|
+
this.portalConfig = new ProductPortalConfigResource(http);
|
|
470
537
|
}
|
|
471
538
|
http;
|
|
539
|
+
/** Per-product portal customization (Garu v0.8.0). */
|
|
540
|
+
portalConfig;
|
|
472
541
|
/**
|
|
473
542
|
* List products for the authenticated seller, with pagination and search.
|
|
474
543
|
*
|
|
@@ -733,6 +802,32 @@ var ScheduledCharges = class {
|
|
|
733
802
|
}).then((r) => r)
|
|
734
803
|
);
|
|
735
804
|
}
|
|
805
|
+
/**
|
|
806
|
+
* Per-attempt billing log for the series (SPEC §4.2). One row per
|
|
807
|
+
* logical billing event — cycle 1 interactive charge, every silent
|
|
808
|
+
* charge attempt, every retry, every manual mark-paid. Carries the
|
|
809
|
+
* canonical `failureCode` for declines so you can audit billing
|
|
810
|
+
* outcomes without cross-referencing Transactions.
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* const { data } = await garu.scheduledCharges.listAttempts('sch_abc', {
|
|
814
|
+
* cycleNumber: 3
|
|
815
|
+
* });
|
|
816
|
+
* const declines = data.filter((a) => a.status === 'declined');
|
|
817
|
+
*/
|
|
818
|
+
async listAttempts(id, params = {}) {
|
|
819
|
+
const qs = new URLSearchParams();
|
|
820
|
+
if (params.page !== void 0) qs.set("page", String(params.page));
|
|
821
|
+
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
822
|
+
if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
|
|
823
|
+
const query = qs.toString();
|
|
824
|
+
const url = `/api/scheduled-charges/${id}/attempts${query ? `?${query}` : ""}`;
|
|
825
|
+
return this.http.call(
|
|
826
|
+
(signal) => this.http.client.GET(url, { signal }).then(
|
|
827
|
+
(r) => r
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
}
|
|
736
831
|
};
|
|
737
832
|
var webhooks = {
|
|
738
833
|
verify(params) {
|
package/dist/index.d.cts
CHANGED
|
@@ -354,6 +354,33 @@ interface ScheduledChargeDetail {
|
|
|
354
354
|
transactions: ScheduledChargeLinkedTransaction[];
|
|
355
355
|
}
|
|
356
356
|
type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
|
|
357
|
+
/** Source of a billing attempt — see SPEC §3.1. */
|
|
358
|
+
type ScheduledChargeAttemptSource = 'cycle1_interactive' | 'silent_charge' | 'card_retry' | 'manual_mark_paid' | 'fallback_pix';
|
|
359
|
+
type ScheduledChargeAttemptStatus = 'pending' | 'succeeded' | 'declined' | 'canceled' | 'errored';
|
|
360
|
+
interface ScheduledChargeAttempt {
|
|
361
|
+
id: number;
|
|
362
|
+
cycleId: string;
|
|
363
|
+
cycleNumber: number;
|
|
364
|
+
attemptNumber: number;
|
|
365
|
+
attemptedAt: string;
|
|
366
|
+
source: ScheduledChargeAttemptSource;
|
|
367
|
+
paymentMethod: 'card' | 'pix' | 'boleto' | 'manual';
|
|
368
|
+
paymentMethodId: number | null;
|
|
369
|
+
cardLast4: string | null;
|
|
370
|
+
cardBrand: string | null;
|
|
371
|
+
status: ScheduledChargeAttemptStatus;
|
|
372
|
+
failureCode: GaruFailureCode | null;
|
|
373
|
+
failureReason: string | null;
|
|
374
|
+
gatewayFailureCode: string | null;
|
|
375
|
+
gatewayChargeId: number | null;
|
|
376
|
+
transactionId: number | null;
|
|
377
|
+
}
|
|
378
|
+
type ScheduledChargeAttemptList = PaginatedList<ScheduledChargeAttempt>;
|
|
379
|
+
interface ListScheduledChargeAttemptsParams {
|
|
380
|
+
page?: number;
|
|
381
|
+
limit?: number;
|
|
382
|
+
cycleNumber?: number;
|
|
383
|
+
}
|
|
357
384
|
interface CreateScheduledChargeParams {
|
|
358
385
|
customerId: number;
|
|
359
386
|
/**
|
|
@@ -485,6 +512,98 @@ interface MetaResponse {
|
|
|
485
512
|
dashboard_url: string;
|
|
486
513
|
support_email: string;
|
|
487
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Canonical Garu failure code on `transaction.payment.failed` and
|
|
517
|
+
* `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
|
|
518
|
+
* branch on this rather than the raw Celcoin code.
|
|
519
|
+
*/
|
|
520
|
+
type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
|
|
521
|
+
/**
|
|
522
|
+
* Shape of the failure trio added to `transaction.payment.failed` and
|
|
523
|
+
* `scheduled_charge.cycle_failed` payloads. Sellers should always receive
|
|
524
|
+
* a non-null `failureCode` — `unknown` is the sentinel when the gateway
|
|
525
|
+
* didn't surface enough detail to map.
|
|
526
|
+
*/
|
|
527
|
+
interface FailurePayload {
|
|
528
|
+
failureCode: GaruFailureCode;
|
|
529
|
+
failureReason: string | null;
|
|
530
|
+
/** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
|
|
531
|
+
gatewayFailureCode: string | null;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* `payment_method.expiring_soon` — fires at 30/14/7 days before card
|
|
535
|
+
* expiry, idempotent per stage. Use to nudge the customer to update
|
|
536
|
+
* their card before silent-charge starts failing.
|
|
537
|
+
*/
|
|
538
|
+
interface PaymentMethodExpiringPayload {
|
|
539
|
+
paymentMethodId: number;
|
|
540
|
+
customerId: number;
|
|
541
|
+
cardLast4: string;
|
|
542
|
+
cardBrand: string;
|
|
543
|
+
expiresAt: string;
|
|
544
|
+
daysUntilExpiry: 30 | 14 | 7;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* `payment_method.expired` — fires once on the day-of-expiry when the cron
|
|
548
|
+
* flips `status='expired'`. Future silent charges short-circuit
|
|
549
|
+
* with `failureCode='card_expired'` instead of hitting the acquirer.
|
|
550
|
+
*/
|
|
551
|
+
interface PaymentMethodExpiredPayload {
|
|
552
|
+
paymentMethodId: number;
|
|
553
|
+
customerId: number;
|
|
554
|
+
cardLast4: string;
|
|
555
|
+
cardBrand: string;
|
|
556
|
+
expiresAt: string;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Per-product portal customization (Atletia coach-as-product modeling and
|
|
560
|
+
* any other B2B2C platform). `null` fields inherit from the seller-level
|
|
561
|
+
* portal config.
|
|
562
|
+
*/
|
|
563
|
+
interface ProductPortalConfig {
|
|
564
|
+
id: number;
|
|
565
|
+
productId: number;
|
|
566
|
+
businessName: string | null;
|
|
567
|
+
logoUrl: string | null;
|
|
568
|
+
primaryColor: string | null;
|
|
569
|
+
allowCancelSubscription: boolean | null;
|
|
570
|
+
allowUpdatePaymentMethod: boolean | null;
|
|
571
|
+
allowUpdateBillingInfo: boolean | null;
|
|
572
|
+
allowViewInvoices: boolean | null;
|
|
573
|
+
allowApplyCoupons: boolean | null;
|
|
574
|
+
requireCancelReason: boolean | null;
|
|
575
|
+
cancelAtPeriodEndOnly: boolean | null;
|
|
576
|
+
sendCancellationEmail: boolean | null;
|
|
577
|
+
sendPaymentMethodUpdatedEmail: boolean | null;
|
|
578
|
+
customSuccessMessage: string | null;
|
|
579
|
+
customCancellationMessage: string | null;
|
|
580
|
+
customWelcomeText: string | null;
|
|
581
|
+
createdAt: string;
|
|
582
|
+
updatedAt: string;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
|
|
586
|
+
* are upsert with merge semantics — only fields present are written;
|
|
587
|
+
* unspecified fields keep their persisted value. Use the `clear`
|
|
588
|
+
* method (DELETE) to reset everything.
|
|
589
|
+
*/
|
|
590
|
+
interface SetProductPortalConfigParams {
|
|
591
|
+
businessName?: string | null;
|
|
592
|
+
logoUrl?: string | null;
|
|
593
|
+
primaryColor?: string | null;
|
|
594
|
+
allowCancelSubscription?: boolean | null;
|
|
595
|
+
allowUpdatePaymentMethod?: boolean | null;
|
|
596
|
+
allowUpdateBillingInfo?: boolean | null;
|
|
597
|
+
allowViewInvoices?: boolean | null;
|
|
598
|
+
allowApplyCoupons?: boolean | null;
|
|
599
|
+
requireCancelReason?: boolean | null;
|
|
600
|
+
cancelAtPeriodEndOnly?: boolean | null;
|
|
601
|
+
sendCancellationEmail?: boolean | null;
|
|
602
|
+
sendPaymentMethodUpdatedEmail?: boolean | null;
|
|
603
|
+
customSuccessMessage?: string | null;
|
|
604
|
+
customCancellationMessage?: string | null;
|
|
605
|
+
customWelcomeText?: string | null;
|
|
606
|
+
}
|
|
488
607
|
|
|
489
608
|
/**
|
|
490
609
|
* Charges — the core of the Garu API.
|
|
@@ -657,13 +776,61 @@ declare class Meta {
|
|
|
657
776
|
}
|
|
658
777
|
|
|
659
778
|
/**
|
|
660
|
-
*
|
|
779
|
+
* Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
|
|
780
|
+
* that model their professionals/coaches as Products under a single seller
|
|
781
|
+
* and want per-product branding on the customer payment + portal pages.
|
|
782
|
+
*/
|
|
783
|
+
declare class ProductPortalConfigResource {
|
|
784
|
+
private readonly http;
|
|
785
|
+
constructor(http: HttpClient);
|
|
786
|
+
/**
|
|
787
|
+
* Get the portal customization for a product. Returns `null` when no
|
|
788
|
+
* per-product config exists (the product falls back to seller-level
|
|
789
|
+
* portal config).
|
|
790
|
+
*
|
|
791
|
+
* @example
|
|
792
|
+
* const cfg = await garu.products.portalConfig.get(57);
|
|
793
|
+
*/
|
|
794
|
+
get(productId: number): Promise<ProductPortalConfig | null>;
|
|
795
|
+
/**
|
|
796
|
+
* Create or merge the portal customization (idempotent upsert). Both
|
|
797
|
+
* `set` and `patch` have the same merge semantics — only fields present
|
|
798
|
+
* in the body are written, unspecified fields keep their persisted
|
|
799
|
+
* value. Use `clear` to reset everything.
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* await garu.products.portalConfig.set(57, {
|
|
803
|
+
* businessName: 'Coach Maria — Corrida & Trilha',
|
|
804
|
+
* primaryColor: '#257264',
|
|
805
|
+
* logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
|
|
806
|
+
* });
|
|
807
|
+
*/
|
|
808
|
+
set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
|
|
809
|
+
/** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
|
|
810
|
+
patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
|
|
811
|
+
/**
|
|
812
|
+
* Remove the per-product config. The product falls back to the
|
|
813
|
+
* seller-level portal config. Returns `{ removed: true }` when a row was
|
|
814
|
+
* deleted, `{ removed: false }` when there was nothing to remove.
|
|
815
|
+
*
|
|
816
|
+
* @example
|
|
817
|
+
* await garu.products.portalConfig.clear(57);
|
|
818
|
+
*/
|
|
819
|
+
clear(productId: number): Promise<{
|
|
820
|
+
removed: boolean;
|
|
821
|
+
}>;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Products — discover products available to charge, and customize the
|
|
825
|
+
* per-product portal experience (v0.8.0).
|
|
661
826
|
*
|
|
662
827
|
* Products are scoped to the seller identified by the API key. The UUID
|
|
663
828
|
* returned here is the same identifier accepted by `charges.create({ productId })`.
|
|
664
829
|
*/
|
|
665
830
|
declare class Products {
|
|
666
831
|
private readonly http;
|
|
832
|
+
/** Per-product portal customization (Garu v0.8.0). */
|
|
833
|
+
readonly portalConfig: ProductPortalConfigResource;
|
|
667
834
|
constructor(http: HttpClient);
|
|
668
835
|
/**
|
|
669
836
|
* List products for the authenticated seller, with pagination and search.
|
|
@@ -831,6 +998,20 @@ declare class ScheduledCharges {
|
|
|
831
998
|
* await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
|
|
832
999
|
*/
|
|
833
1000
|
clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Per-attempt billing log for the series (SPEC §4.2). One row per
|
|
1003
|
+
* logical billing event — cycle 1 interactive charge, every silent
|
|
1004
|
+
* charge attempt, every retry, every manual mark-paid. Carries the
|
|
1005
|
+
* canonical `failureCode` for declines so you can audit billing
|
|
1006
|
+
* outcomes without cross-referencing Transactions.
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* const { data } = await garu.scheduledCharges.listAttempts('sch_abc', {
|
|
1010
|
+
* cycleNumber: 3
|
|
1011
|
+
* });
|
|
1012
|
+
* const declines = data.filter((a) => a.status === 'declined');
|
|
1013
|
+
*/
|
|
1014
|
+
listAttempts(id: string, params?: ListScheduledChargeAttemptsParams): Promise<ScheduledChargeAttemptList>;
|
|
834
1015
|
}
|
|
835
1016
|
|
|
836
1017
|
interface GaruOptions {
|
|
@@ -931,4 +1112,4 @@ declare class GaruServerError extends GaruAPIError {
|
|
|
931
1112
|
constructor(message: string, status: number, requestId: string | null, body: unknown);
|
|
932
1113
|
}
|
|
933
1114
|
|
|
934
|
-
export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
|
|
1115
|
+
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 MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type 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 WirePaymentMethodId, webhooks };
|
package/dist/index.d.ts
CHANGED
|
@@ -354,6 +354,33 @@ interface ScheduledChargeDetail {
|
|
|
354
354
|
transactions: ScheduledChargeLinkedTransaction[];
|
|
355
355
|
}
|
|
356
356
|
type ScheduledChargeList = PaginatedList<ScheduledChargeRecord>;
|
|
357
|
+
/** Source of a billing attempt — see SPEC §3.1. */
|
|
358
|
+
type ScheduledChargeAttemptSource = 'cycle1_interactive' | 'silent_charge' | 'card_retry' | 'manual_mark_paid' | 'fallback_pix';
|
|
359
|
+
type ScheduledChargeAttemptStatus = 'pending' | 'succeeded' | 'declined' | 'canceled' | 'errored';
|
|
360
|
+
interface ScheduledChargeAttempt {
|
|
361
|
+
id: number;
|
|
362
|
+
cycleId: string;
|
|
363
|
+
cycleNumber: number;
|
|
364
|
+
attemptNumber: number;
|
|
365
|
+
attemptedAt: string;
|
|
366
|
+
source: ScheduledChargeAttemptSource;
|
|
367
|
+
paymentMethod: 'card' | 'pix' | 'boleto' | 'manual';
|
|
368
|
+
paymentMethodId: number | null;
|
|
369
|
+
cardLast4: string | null;
|
|
370
|
+
cardBrand: string | null;
|
|
371
|
+
status: ScheduledChargeAttemptStatus;
|
|
372
|
+
failureCode: GaruFailureCode | null;
|
|
373
|
+
failureReason: string | null;
|
|
374
|
+
gatewayFailureCode: string | null;
|
|
375
|
+
gatewayChargeId: number | null;
|
|
376
|
+
transactionId: number | null;
|
|
377
|
+
}
|
|
378
|
+
type ScheduledChargeAttemptList = PaginatedList<ScheduledChargeAttempt>;
|
|
379
|
+
interface ListScheduledChargeAttemptsParams {
|
|
380
|
+
page?: number;
|
|
381
|
+
limit?: number;
|
|
382
|
+
cycleNumber?: number;
|
|
383
|
+
}
|
|
357
384
|
interface CreateScheduledChargeParams {
|
|
358
385
|
customerId: number;
|
|
359
386
|
/**
|
|
@@ -485,6 +512,98 @@ interface MetaResponse {
|
|
|
485
512
|
dashboard_url: string;
|
|
486
513
|
support_email: string;
|
|
487
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Canonical Garu failure code on `transaction.payment.failed` and
|
|
517
|
+
* `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
|
|
518
|
+
* branch on this rather than the raw Celcoin code.
|
|
519
|
+
*/
|
|
520
|
+
type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
|
|
521
|
+
/**
|
|
522
|
+
* Shape of the failure trio added to `transaction.payment.failed` and
|
|
523
|
+
* `scheduled_charge.cycle_failed` payloads. Sellers should always receive
|
|
524
|
+
* a non-null `failureCode` — `unknown` is the sentinel when the gateway
|
|
525
|
+
* didn't surface enough detail to map.
|
|
526
|
+
*/
|
|
527
|
+
interface FailurePayload {
|
|
528
|
+
failureCode: GaruFailureCode;
|
|
529
|
+
failureReason: string | null;
|
|
530
|
+
/** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
|
|
531
|
+
gatewayFailureCode: string | null;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* `payment_method.expiring_soon` — fires at 30/14/7 days before card
|
|
535
|
+
* expiry, idempotent per stage. Use to nudge the customer to update
|
|
536
|
+
* their card before silent-charge starts failing.
|
|
537
|
+
*/
|
|
538
|
+
interface PaymentMethodExpiringPayload {
|
|
539
|
+
paymentMethodId: number;
|
|
540
|
+
customerId: number;
|
|
541
|
+
cardLast4: string;
|
|
542
|
+
cardBrand: string;
|
|
543
|
+
expiresAt: string;
|
|
544
|
+
daysUntilExpiry: 30 | 14 | 7;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* `payment_method.expired` — fires once on the day-of-expiry when the cron
|
|
548
|
+
* flips `status='expired'`. Future silent charges short-circuit
|
|
549
|
+
* with `failureCode='card_expired'` instead of hitting the acquirer.
|
|
550
|
+
*/
|
|
551
|
+
interface PaymentMethodExpiredPayload {
|
|
552
|
+
paymentMethodId: number;
|
|
553
|
+
customerId: number;
|
|
554
|
+
cardLast4: string;
|
|
555
|
+
cardBrand: string;
|
|
556
|
+
expiresAt: string;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Per-product portal customization (Atletia coach-as-product modeling and
|
|
560
|
+
* any other B2B2C platform). `null` fields inherit from the seller-level
|
|
561
|
+
* portal config.
|
|
562
|
+
*/
|
|
563
|
+
interface ProductPortalConfig {
|
|
564
|
+
id: number;
|
|
565
|
+
productId: number;
|
|
566
|
+
businessName: string | null;
|
|
567
|
+
logoUrl: string | null;
|
|
568
|
+
primaryColor: string | null;
|
|
569
|
+
allowCancelSubscription: boolean | null;
|
|
570
|
+
allowUpdatePaymentMethod: boolean | null;
|
|
571
|
+
allowUpdateBillingInfo: boolean | null;
|
|
572
|
+
allowViewInvoices: boolean | null;
|
|
573
|
+
allowApplyCoupons: boolean | null;
|
|
574
|
+
requireCancelReason: boolean | null;
|
|
575
|
+
cancelAtPeriodEndOnly: boolean | null;
|
|
576
|
+
sendCancellationEmail: boolean | null;
|
|
577
|
+
sendPaymentMethodUpdatedEmail: boolean | null;
|
|
578
|
+
customSuccessMessage: string | null;
|
|
579
|
+
customCancellationMessage: string | null;
|
|
580
|
+
customWelcomeText: string | null;
|
|
581
|
+
createdAt: string;
|
|
582
|
+
updatedAt: string;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
|
|
586
|
+
* are upsert with merge semantics — only fields present are written;
|
|
587
|
+
* unspecified fields keep their persisted value. Use the `clear`
|
|
588
|
+
* method (DELETE) to reset everything.
|
|
589
|
+
*/
|
|
590
|
+
interface SetProductPortalConfigParams {
|
|
591
|
+
businessName?: string | null;
|
|
592
|
+
logoUrl?: string | null;
|
|
593
|
+
primaryColor?: string | null;
|
|
594
|
+
allowCancelSubscription?: boolean | null;
|
|
595
|
+
allowUpdatePaymentMethod?: boolean | null;
|
|
596
|
+
allowUpdateBillingInfo?: boolean | null;
|
|
597
|
+
allowViewInvoices?: boolean | null;
|
|
598
|
+
allowApplyCoupons?: boolean | null;
|
|
599
|
+
requireCancelReason?: boolean | null;
|
|
600
|
+
cancelAtPeriodEndOnly?: boolean | null;
|
|
601
|
+
sendCancellationEmail?: boolean | null;
|
|
602
|
+
sendPaymentMethodUpdatedEmail?: boolean | null;
|
|
603
|
+
customSuccessMessage?: string | null;
|
|
604
|
+
customCancellationMessage?: string | null;
|
|
605
|
+
customWelcomeText?: string | null;
|
|
606
|
+
}
|
|
488
607
|
|
|
489
608
|
/**
|
|
490
609
|
* Charges — the core of the Garu API.
|
|
@@ -657,13 +776,61 @@ declare class Meta {
|
|
|
657
776
|
}
|
|
658
777
|
|
|
659
778
|
/**
|
|
660
|
-
*
|
|
779
|
+
* Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
|
|
780
|
+
* that model their professionals/coaches as Products under a single seller
|
|
781
|
+
* and want per-product branding on the customer payment + portal pages.
|
|
782
|
+
*/
|
|
783
|
+
declare class ProductPortalConfigResource {
|
|
784
|
+
private readonly http;
|
|
785
|
+
constructor(http: HttpClient);
|
|
786
|
+
/**
|
|
787
|
+
* Get the portal customization for a product. Returns `null` when no
|
|
788
|
+
* per-product config exists (the product falls back to seller-level
|
|
789
|
+
* portal config).
|
|
790
|
+
*
|
|
791
|
+
* @example
|
|
792
|
+
* const cfg = await garu.products.portalConfig.get(57);
|
|
793
|
+
*/
|
|
794
|
+
get(productId: number): Promise<ProductPortalConfig | null>;
|
|
795
|
+
/**
|
|
796
|
+
* Create or merge the portal customization (idempotent upsert). Both
|
|
797
|
+
* `set` and `patch` have the same merge semantics — only fields present
|
|
798
|
+
* in the body are written, unspecified fields keep their persisted
|
|
799
|
+
* value. Use `clear` to reset everything.
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* await garu.products.portalConfig.set(57, {
|
|
803
|
+
* businessName: 'Coach Maria — Corrida & Trilha',
|
|
804
|
+
* primaryColor: '#257264',
|
|
805
|
+
* logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
|
|
806
|
+
* });
|
|
807
|
+
*/
|
|
808
|
+
set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
|
|
809
|
+
/** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
|
|
810
|
+
patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
|
|
811
|
+
/**
|
|
812
|
+
* Remove the per-product config. The product falls back to the
|
|
813
|
+
* seller-level portal config. Returns `{ removed: true }` when a row was
|
|
814
|
+
* deleted, `{ removed: false }` when there was nothing to remove.
|
|
815
|
+
*
|
|
816
|
+
* @example
|
|
817
|
+
* await garu.products.portalConfig.clear(57);
|
|
818
|
+
*/
|
|
819
|
+
clear(productId: number): Promise<{
|
|
820
|
+
removed: boolean;
|
|
821
|
+
}>;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Products — discover products available to charge, and customize the
|
|
825
|
+
* per-product portal experience (v0.8.0).
|
|
661
826
|
*
|
|
662
827
|
* Products are scoped to the seller identified by the API key. The UUID
|
|
663
828
|
* returned here is the same identifier accepted by `charges.create({ productId })`.
|
|
664
829
|
*/
|
|
665
830
|
declare class Products {
|
|
666
831
|
private readonly http;
|
|
832
|
+
/** Per-product portal customization (Garu v0.8.0). */
|
|
833
|
+
readonly portalConfig: ProductPortalConfigResource;
|
|
667
834
|
constructor(http: HttpClient);
|
|
668
835
|
/**
|
|
669
836
|
* List products for the authenticated seller, with pagination and search.
|
|
@@ -831,6 +998,20 @@ declare class ScheduledCharges {
|
|
|
831
998
|
* await garu.scheduledCharges.clearPaymentMethod('sch_abc123');
|
|
832
999
|
*/
|
|
833
1000
|
clearPaymentMethod(id: string): Promise<ScheduledChargeRecord>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Per-attempt billing log for the series (SPEC §4.2). One row per
|
|
1003
|
+
* logical billing event — cycle 1 interactive charge, every silent
|
|
1004
|
+
* charge attempt, every retry, every manual mark-paid. Carries the
|
|
1005
|
+
* canonical `failureCode` for declines so you can audit billing
|
|
1006
|
+
* outcomes without cross-referencing Transactions.
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* const { data } = await garu.scheduledCharges.listAttempts('sch_abc', {
|
|
1010
|
+
* cycleNumber: 3
|
|
1011
|
+
* });
|
|
1012
|
+
* const declines = data.filter((a) => a.status === 'declined');
|
|
1013
|
+
*/
|
|
1014
|
+
listAttempts(id: string, params?: ListScheduledChargeAttemptsParams): Promise<ScheduledChargeAttemptList>;
|
|
834
1015
|
}
|
|
835
1016
|
|
|
836
1017
|
interface GaruOptions {
|
|
@@ -931,4 +1112,4 @@ declare class GaruServerError extends GaruAPIError {
|
|
|
931
1112
|
constructor(message: string, status: number, requestId: string | null, body: unknown);
|
|
932
1113
|
}
|
|
933
1114
|
|
|
934
|
-
export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
|
|
1115
|
+
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 MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type 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 WirePaymentMethodId, webhooks };
|
package/dist/index.js
CHANGED
|
@@ -458,11 +458,80 @@ var Meta = class {
|
|
|
458
458
|
};
|
|
459
459
|
|
|
460
460
|
// src/resources/products.ts
|
|
461
|
+
var ProductPortalConfigResource = class {
|
|
462
|
+
constructor(http) {
|
|
463
|
+
this.http = http;
|
|
464
|
+
}
|
|
465
|
+
http;
|
|
466
|
+
/**
|
|
467
|
+
* Get the portal customization for a product. Returns `null` when no
|
|
468
|
+
* per-product config exists (the product falls back to seller-level
|
|
469
|
+
* portal config).
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* const cfg = await garu.products.portalConfig.get(57);
|
|
473
|
+
*/
|
|
474
|
+
async get(productId) {
|
|
475
|
+
return this.http.call(
|
|
476
|
+
(signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
|
|
477
|
+
signal
|
|
478
|
+
}).then((r) => r)
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Create or merge the portal customization (idempotent upsert). Both
|
|
483
|
+
* `set` and `patch` have the same merge semantics — only fields present
|
|
484
|
+
* in the body are written, unspecified fields keep their persisted
|
|
485
|
+
* value. Use `clear` to reset everything.
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* await garu.products.portalConfig.set(57, {
|
|
489
|
+
* businessName: 'Coach Maria — Corrida & Trilha',
|
|
490
|
+
* primaryColor: '#257264',
|
|
491
|
+
* logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
|
|
492
|
+
* });
|
|
493
|
+
*/
|
|
494
|
+
async set(productId, params) {
|
|
495
|
+
return this.http.call(
|
|
496
|
+
(signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
|
|
497
|
+
body: params,
|
|
498
|
+
signal
|
|
499
|
+
}).then((r) => r)
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
/** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
|
|
503
|
+
async patch(productId, params) {
|
|
504
|
+
return this.http.call(
|
|
505
|
+
(signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
|
|
506
|
+
body: params,
|
|
507
|
+
signal
|
|
508
|
+
}).then((r) => r)
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Remove the per-product config. The product falls back to the
|
|
513
|
+
* seller-level portal config. Returns `{ removed: true }` when a row was
|
|
514
|
+
* deleted, `{ removed: false }` when there was nothing to remove.
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* await garu.products.portalConfig.clear(57);
|
|
518
|
+
*/
|
|
519
|
+
async clear(productId) {
|
|
520
|
+
return this.http.call(
|
|
521
|
+
(signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
|
|
522
|
+
signal
|
|
523
|
+
}).then((r) => r)
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
461
527
|
var Products = class {
|
|
462
528
|
constructor(http) {
|
|
463
529
|
this.http = http;
|
|
530
|
+
this.portalConfig = new ProductPortalConfigResource(http);
|
|
464
531
|
}
|
|
465
532
|
http;
|
|
533
|
+
/** Per-product portal customization (Garu v0.8.0). */
|
|
534
|
+
portalConfig;
|
|
466
535
|
/**
|
|
467
536
|
* List products for the authenticated seller, with pagination and search.
|
|
468
537
|
*
|
|
@@ -727,6 +796,32 @@ var ScheduledCharges = class {
|
|
|
727
796
|
}).then((r) => r)
|
|
728
797
|
);
|
|
729
798
|
}
|
|
799
|
+
/**
|
|
800
|
+
* Per-attempt billing log for the series (SPEC §4.2). One row per
|
|
801
|
+
* logical billing event — cycle 1 interactive charge, every silent
|
|
802
|
+
* charge attempt, every retry, every manual mark-paid. Carries the
|
|
803
|
+
* canonical `failureCode` for declines so you can audit billing
|
|
804
|
+
* outcomes without cross-referencing Transactions.
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* const { data } = await garu.scheduledCharges.listAttempts('sch_abc', {
|
|
808
|
+
* cycleNumber: 3
|
|
809
|
+
* });
|
|
810
|
+
* const declines = data.filter((a) => a.status === 'declined');
|
|
811
|
+
*/
|
|
812
|
+
async listAttempts(id, params = {}) {
|
|
813
|
+
const qs = new URLSearchParams();
|
|
814
|
+
if (params.page !== void 0) qs.set("page", String(params.page));
|
|
815
|
+
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
816
|
+
if (params.cycleNumber !== void 0) qs.set("cycleNumber", String(params.cycleNumber));
|
|
817
|
+
const query = qs.toString();
|
|
818
|
+
const url = `/api/scheduled-charges/${id}/attempts${query ? `?${query}` : ""}`;
|
|
819
|
+
return this.http.call(
|
|
820
|
+
(signal) => this.http.client.GET(url, { signal }).then(
|
|
821
|
+
(r) => r
|
|
822
|
+
)
|
|
823
|
+
);
|
|
824
|
+
}
|
|
730
825
|
};
|
|
731
826
|
var webhooks = {
|
|
732
827
|
verify(params) {
|