@garuhq/node 2.0.0 → 3.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 +43 -0
- package/README.md +8 -7
- package/dist/index.cjs +33 -44
- package/dist/index.d.cts +45 -33
- package/dist/index.d.ts +45 -33
- package/dist/index.js +33 -44
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
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
|
+
## [3.0.0] — 2026-08-22
|
|
7
|
+
|
|
8
|
+
**Breaking:** `webhookEvents` now targets the versioned public API
|
|
9
|
+
`/api/v1/webhook-events`, keyed on `uuid`. If you use `garu.webhookEvents.*`,
|
|
10
|
+
read the migration below.
|
|
11
|
+
|
|
12
|
+
### Breaking
|
|
13
|
+
|
|
14
|
+
- **`webhookEvents` moved to `/api/v1/webhook-events`** and an event is
|
|
15
|
+
keyed by **`uuid`**, not a numeric `id`.
|
|
16
|
+
- `webhookEvents.get(id: number)` → **`webhookEvents.get(uuid: string)`**.
|
|
17
|
+
- `webhookEvents.retry(id)` / `webhookEvents.resend(id, params?)` — same
|
|
18
|
+
signature shape, but the id argument is now the `uuid`.
|
|
19
|
+
- `WebhookEvent.id` is **removed**; there is no numeric id in the public
|
|
20
|
+
shape. Use `WebhookEvent.uuid` everywhere. `WebhookEvent.endpointId` is
|
|
21
|
+
also removed — read `webhookEndpoint.id` instead (endpoint configuration
|
|
22
|
+
stays numeric; it did not move to `/api/v1`).
|
|
23
|
+
- `WebhookEvent.manualResendOf` is now a **`uuid` string** (was a numeric
|
|
24
|
+
id), pointing at the source event's `uuid`.
|
|
25
|
+
- **`webhookEvents.list()` returns `{ data, count, totalCount, totalPages }`**
|
|
26
|
+
(was `{ data, meta }`).
|
|
27
|
+
- The gateway's outbound `Idempotency-Key` for `/resend` clones is now
|
|
28
|
+
`resend_<uuid>` (was `resend_<numeric id>`), to match the public
|
|
29
|
+
identifier the SDK/CLI/MCP now expose.
|
|
30
|
+
|
|
31
|
+
### Migration
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// before (0.x – 2.x)
|
|
35
|
+
const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
36
|
+
const event = failed.data[0];
|
|
37
|
+
event.id; // number
|
|
38
|
+
const clone = await garu.webhookEvents.resend(event.id);
|
|
39
|
+
clone.manualResendOf === event.id; // true
|
|
40
|
+
|
|
41
|
+
// after (3.0.0)
|
|
42
|
+
const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
43
|
+
const event = failed.data[0];
|
|
44
|
+
event.uuid; // string
|
|
45
|
+
const clone = await garu.webhookEvents.resend(event.uuid);
|
|
46
|
+
clone.manualResendOf === event.uuid; // true
|
|
47
|
+
```
|
|
48
|
+
|
|
6
49
|
## [2.0.0] — 2026-08-22
|
|
7
50
|
|
|
8
51
|
**Breaking:** `customers` now targets the versioned public API `/api/v1/customers`,
|
package/README.md
CHANGED
|
@@ -397,18 +397,19 @@ The seller-facing delivery log for outbound webhooks. Use it to audit deliveries
|
|
|
397
397
|
const failed = await garu.webhookEvents.list({ status: 'failed', limit: 50 });
|
|
398
398
|
|
|
399
399
|
// Inspect one event end-to-end
|
|
400
|
-
const event = await garu.webhookEvents.get(
|
|
401
|
-
|
|
400
|
+
const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
401
|
+
event.responseStatus;
|
|
402
|
+
event.responseBody;
|
|
402
403
|
|
|
403
404
|
// Audit-trail-preserving replay (recommended)
|
|
404
|
-
const clone = await garu.webhookEvents.resend(
|
|
405
|
-
clone.
|
|
406
|
-
clone.manualResendOf === event.
|
|
405
|
+
const clone = await garu.webhookEvents.resend(event.uuid);
|
|
406
|
+
clone.uuid !== event.uuid; // true — fresh row with its own uuid
|
|
407
|
+
clone.manualResendOf === event.uuid; // true — points back at the source
|
|
407
408
|
```
|
|
408
409
|
|
|
409
|
-
`resend(
|
|
410
|
+
`resend(uuid)` is the audit-preserving counterpart to `retry(uuid)` — the backend inserts a fresh event whose `manualResendOf` points back at the source, then dispatches that clone. The original row stays exactly as it was, so the historical record of the prior failure (status, response status/body, attempts) survives. Works on any source status (`success` / `failed` / `pending`).
|
|
410
411
|
|
|
411
|
-
Outbound deliveries of a resent event carry `Idempotency-Key: resend_<
|
|
412
|
+
Outbound deliveries of a resent event carry `Idempotency-Key: resend_<cloneUuid>`, so recipient handlers can distinguish a resend from a fresh delivery both by the header prefix and by reading the response payload's `manualResendOf` field.
|
|
412
413
|
|
|
413
414
|
> [!NOTE]
|
|
414
415
|
> 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.
|
package/dist/index.cjs
CHANGED
|
@@ -1293,42 +1293,31 @@ var WebhookEvents = class {
|
|
|
1293
1293
|
* });
|
|
1294
1294
|
*/
|
|
1295
1295
|
async list(params = {}) {
|
|
1296
|
-
const
|
|
1297
|
-
if (params.page !== void 0)
|
|
1298
|
-
if (params.limit !== void 0)
|
|
1299
|
-
if (params.status)
|
|
1300
|
-
if (params.eventType)
|
|
1301
|
-
if (params.endpointId !== void 0)
|
|
1302
|
-
const
|
|
1303
|
-
const url = `/api/webhook-events${
|
|
1304
|
-
|
|
1296
|
+
const query = {};
|
|
1297
|
+
if (params.page !== void 0) query.page = String(params.page);
|
|
1298
|
+
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1299
|
+
if (params.status) query.status = params.status;
|
|
1300
|
+
if (params.eventType) query.eventType = params.eventType;
|
|
1301
|
+
if (params.endpointId !== void 0) query.endpointId = String(params.endpointId);
|
|
1302
|
+
const qs = new URLSearchParams(query).toString();
|
|
1303
|
+
const url = `/api/v1/webhook-events${qs ? `?${qs}` : ""}`;
|
|
1304
|
+
return this.http.call(
|
|
1305
1305
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1306
1306
|
(r) => r
|
|
1307
1307
|
)
|
|
1308
1308
|
);
|
|
1309
|
-
return {
|
|
1310
|
-
data: raw.events,
|
|
1311
|
-
meta: {
|
|
1312
|
-
page: raw.page,
|
|
1313
|
-
limit: raw.limit,
|
|
1314
|
-
total: raw.total,
|
|
1315
|
-
totalPages: raw.pages
|
|
1316
|
-
}
|
|
1317
|
-
};
|
|
1318
1309
|
}
|
|
1319
1310
|
/**
|
|
1320
|
-
* Fetch one webhook event by
|
|
1311
|
+
* Fetch one webhook event by uuid — includes the full payload, the
|
|
1321
1312
|
* embedded endpoint snapshot, and the most recent response status/body.
|
|
1322
1313
|
*
|
|
1323
1314
|
* @example
|
|
1324
|
-
* const event = await garu.webhookEvents.get(
|
|
1325
|
-
*
|
|
1326
|
-
* console.log(event.responseStatus, event.responseBody);
|
|
1327
|
-
* }
|
|
1315
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1316
|
+
* event.status === 'failed' && event.responseStatus;
|
|
1328
1317
|
*/
|
|
1329
|
-
async get(
|
|
1318
|
+
async get(uuid) {
|
|
1330
1319
|
return this.http.call(
|
|
1331
|
-
(signal) => this.http.client.GET(`/api/webhook-events/${
|
|
1320
|
+
(signal) => this.http.client.GET(`/api/v1/webhook-events/${uuid}`, { signal }).then(
|
|
1332
1321
|
(r) => r
|
|
1333
1322
|
)
|
|
1334
1323
|
);
|
|
@@ -1341,28 +1330,28 @@ var WebhookEvents = class {
|
|
|
1341
1330
|
* explicitly want the legacy in-place semantics (and for backwards
|
|
1342
1331
|
* compatibility with older CLI / MCP releases).
|
|
1343
1332
|
*
|
|
1344
|
-
* Re-deliver a webhook event by
|
|
1333
|
+
* Re-deliver a webhook event by uuid. Resets it to `pending`, clears the
|
|
1345
1334
|
* retry schedule, and triggers an immediate delivery attempt. Works on
|
|
1346
1335
|
* any status (`success`, `failed`, `pending`).
|
|
1347
1336
|
*
|
|
1348
1337
|
* @example
|
|
1349
1338
|
* const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
1350
1339
|
* for (const event of failed.data) {
|
|
1351
|
-
* await garu.webhookEvents.retry(event.
|
|
1340
|
+
* await garu.webhookEvents.retry(event.uuid);
|
|
1352
1341
|
* }
|
|
1353
1342
|
*/
|
|
1354
|
-
async retry(
|
|
1343
|
+
async retry(uuid) {
|
|
1355
1344
|
return this.http.call(
|
|
1356
|
-
(signal) => this.http.client.POST(`/api/webhook-events/${
|
|
1345
|
+
(signal) => this.http.client.POST(`/api/v1/webhook-events/${uuid}/retry`, {
|
|
1357
1346
|
body: {},
|
|
1358
1347
|
signal
|
|
1359
1348
|
}).then((r) => r)
|
|
1360
1349
|
);
|
|
1361
1350
|
}
|
|
1362
1351
|
/**
|
|
1363
|
-
* Re-deliver a webhook event by
|
|
1352
|
+
* Re-deliver a webhook event by uuid, audit-trail preserving. Unlike
|
|
1364
1353
|
* {@link retry}, this does *not* mutate the original row — it inserts a
|
|
1365
|
-
* fresh event (new
|
|
1354
|
+
* fresh event (new uuid) that points back at the source via
|
|
1366
1355
|
* `manualResendOf`, then dispatches that clone. The original row is
|
|
1367
1356
|
* untouched, so the historical record of the prior failure (and its
|
|
1368
1357
|
* response status / body) is preserved.
|
|
@@ -1373,30 +1362,30 @@ var WebhookEvents = class {
|
|
|
1373
1362
|
* delivery's outcome to remain on the record.
|
|
1374
1363
|
*
|
|
1375
1364
|
* **Outbound delivery semantics**: the gateway POSTs the clone with
|
|
1376
|
-
* `Idempotency-Key: resend_<
|
|
1377
|
-
* of the source event, not the clone). Recipient handlers that key off
|
|
1365
|
+
* `Idempotency-Key: resend_<cloneUuid>`. Recipient handlers that key off
|
|
1378
1366
|
* `Idempotency-Key` will see this as a distinct delivery from the
|
|
1379
1367
|
* original — distinguishable both by the `resend_` prefix and by reading
|
|
1380
1368
|
* the response payload's `manualResendOf` field.
|
|
1381
1369
|
*
|
|
1382
|
-
*
|
|
1383
|
-
*
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
1370
|
+
* The SDK also attaches an `X-Idempotency-Key` header (UUIDv4 unless you
|
|
1371
|
+
* pass `idempotencyKey`); the gateway does not currently deduplicate
|
|
1372
|
+
* `/resend` calls against it, so retrying this call from your own code
|
|
1373
|
+
* after a network failure can create more than one clone — pair it with
|
|
1374
|
+
* your own retry-suppression if that matters for your integration.
|
|
1386
1375
|
*
|
|
1387
|
-
* Returns the *clone* event (new
|
|
1376
|
+
* Returns the *clone* event (new uuid), not the original. The original is
|
|
1388
1377
|
* unchanged on the server.
|
|
1389
1378
|
*
|
|
1390
1379
|
* @example
|
|
1391
|
-
* const event = await garu.webhookEvents.get(
|
|
1392
|
-
* const clone = await garu.webhookEvents.resend(
|
|
1393
|
-
* clone.
|
|
1394
|
-
* clone.manualResendOf === event.
|
|
1380
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1381
|
+
* const clone = await garu.webhookEvents.resend(event.uuid);
|
|
1382
|
+
* clone.uuid !== event.uuid; // true — clone has its own uuid
|
|
1383
|
+
* clone.manualResendOf === event.uuid; // true — points back at the source
|
|
1395
1384
|
*/
|
|
1396
|
-
async resend(
|
|
1385
|
+
async resend(uuid, params = {}) {
|
|
1397
1386
|
const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
|
|
1398
1387
|
return this.http.call(
|
|
1399
|
-
(signal) => this.http.client.POST(`/api/webhook-events/${
|
|
1388
|
+
(signal) => this.http.client.POST(`/api/v1/webhook-events/${uuid}/resend`, {
|
|
1400
1389
|
body: {},
|
|
1401
1390
|
headers: { "X-Idempotency-Key": idempotencyKey },
|
|
1402
1391
|
signal
|
package/dist/index.d.cts
CHANGED
|
@@ -770,9 +770,14 @@ interface WebhookEventEndpoint {
|
|
|
770
770
|
events: string[];
|
|
771
771
|
[key: string]: unknown;
|
|
772
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Public API v1 webhook-event representation. Keyed on `uuid` — there is no
|
|
775
|
+
* numeric id in this shape. `webhookEndpoint.id` stays numeric: endpoint
|
|
776
|
+
* *configuration* (create/update/delete) is still dashboard-only and did
|
|
777
|
+
* not move to `/api/v1`.
|
|
778
|
+
*/
|
|
773
779
|
interface WebhookEvent {
|
|
774
|
-
|
|
775
|
-
endpointId: number;
|
|
780
|
+
uuid: string;
|
|
776
781
|
/** Eager-loaded endpoint snapshot. */
|
|
777
782
|
webhookEndpoint: WebhookEventEndpoint;
|
|
778
783
|
/** Garu event type, e.g. `transaction.payment.paid`. */
|
|
@@ -791,17 +796,24 @@ interface WebhookEvent {
|
|
|
791
796
|
/** Response body from the most recent attempt, truncated by the gateway. */
|
|
792
797
|
responseBody: string | null;
|
|
793
798
|
/**
|
|
794
|
-
* When this row is a clone produced by `webhookEvents.resend(
|
|
795
|
-
* the
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
+
* When this row is a clone produced by `webhookEvents.resend(uuid)`, this
|
|
800
|
+
* is the uuid of the original event the clone was forked from. `null` on
|
|
801
|
+
* every originally-fired event (and on events resurrected via the legacy
|
|
802
|
+
* `webhookEvents.retry(uuid)` mutation, which mutates in place instead of
|
|
803
|
+
* cloning).
|
|
799
804
|
*/
|
|
800
|
-
manualResendOf:
|
|
805
|
+
manualResendOf: string | null;
|
|
801
806
|
createdAt: string;
|
|
802
807
|
[key: string]: unknown;
|
|
803
808
|
}
|
|
804
|
-
|
|
809
|
+
interface WebhookEventList {
|
|
810
|
+
data: WebhookEvent[];
|
|
811
|
+
/** Items on this page. */
|
|
812
|
+
count: number;
|
|
813
|
+
/** Total matches across all pages. */
|
|
814
|
+
totalCount: number;
|
|
815
|
+
totalPages: number;
|
|
816
|
+
}
|
|
805
817
|
interface ListWebhookEventsParams {
|
|
806
818
|
page?: number;
|
|
807
819
|
limit?: number;
|
|
@@ -1754,7 +1766,8 @@ declare class ScheduledCharges {
|
|
|
1754
1766
|
/**
|
|
1755
1767
|
* Webhook events — the seller-facing delivery log for outbound webhooks.
|
|
1756
1768
|
*
|
|
1757
|
-
*
|
|
1769
|
+
* Backed by `/api/v1/webhook-events`, keyed on `uuid`. Every time the
|
|
1770
|
+
* gateway fires a webhook (e.g. `transaction.payment.paid`,
|
|
1758
1771
|
* `scheduled_charge.cycle_failed`), it persists one row per destination
|
|
1759
1772
|
* endpoint with the full payload, the HTTP outcome, and the retry schedule.
|
|
1760
1773
|
* Use this resource to audit deliveries from the seller's API key — the
|
|
@@ -1762,6 +1775,7 @@ declare class ScheduledCharges {
|
|
|
1762
1775
|
*
|
|
1763
1776
|
* Webhook endpoint *configuration* (URL, subscribed events, secret) is still
|
|
1764
1777
|
* dashboard-only — this resource only covers the event log + manual retries.
|
|
1778
|
+
* `webhookEndpoint.id` on every event stays a numeric id for that reason.
|
|
1765
1779
|
*/
|
|
1766
1780
|
declare class WebhookEvents {
|
|
1767
1781
|
private readonly http;
|
|
@@ -1784,16 +1798,14 @@ declare class WebhookEvents {
|
|
|
1784
1798
|
*/
|
|
1785
1799
|
list(params?: ListWebhookEventsParams): Promise<WebhookEventList>;
|
|
1786
1800
|
/**
|
|
1787
|
-
* Fetch one webhook event by
|
|
1801
|
+
* Fetch one webhook event by uuid — includes the full payload, the
|
|
1788
1802
|
* embedded endpoint snapshot, and the most recent response status/body.
|
|
1789
1803
|
*
|
|
1790
1804
|
* @example
|
|
1791
|
-
* const event = await garu.webhookEvents.get(
|
|
1792
|
-
*
|
|
1793
|
-
* console.log(event.responseStatus, event.responseBody);
|
|
1794
|
-
* }
|
|
1805
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1806
|
+
* event.status === 'failed' && event.responseStatus;
|
|
1795
1807
|
*/
|
|
1796
|
-
get(
|
|
1808
|
+
get(uuid: string): Promise<WebhookEvent>;
|
|
1797
1809
|
/**
|
|
1798
1810
|
* @deprecated For most cases prefer {@link resend}, which preserves the
|
|
1799
1811
|
* original event's audit trail by cloning rather than mutating. `retry()`
|
|
@@ -1802,21 +1814,21 @@ declare class WebhookEvents {
|
|
|
1802
1814
|
* explicitly want the legacy in-place semantics (and for backwards
|
|
1803
1815
|
* compatibility with older CLI / MCP releases).
|
|
1804
1816
|
*
|
|
1805
|
-
* Re-deliver a webhook event by
|
|
1817
|
+
* Re-deliver a webhook event by uuid. Resets it to `pending`, clears the
|
|
1806
1818
|
* retry schedule, and triggers an immediate delivery attempt. Works on
|
|
1807
1819
|
* any status (`success`, `failed`, `pending`).
|
|
1808
1820
|
*
|
|
1809
1821
|
* @example
|
|
1810
1822
|
* const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
1811
1823
|
* for (const event of failed.data) {
|
|
1812
|
-
* await garu.webhookEvents.retry(event.
|
|
1824
|
+
* await garu.webhookEvents.retry(event.uuid);
|
|
1813
1825
|
* }
|
|
1814
1826
|
*/
|
|
1815
|
-
retry(
|
|
1827
|
+
retry(uuid: string): Promise<WebhookEvent>;
|
|
1816
1828
|
/**
|
|
1817
|
-
* Re-deliver a webhook event by
|
|
1829
|
+
* Re-deliver a webhook event by uuid, audit-trail preserving. Unlike
|
|
1818
1830
|
* {@link retry}, this does *not* mutate the original row — it inserts a
|
|
1819
|
-
* fresh event (new
|
|
1831
|
+
* fresh event (new uuid) that points back at the source via
|
|
1820
1832
|
* `manualResendOf`, then dispatches that clone. The original row is
|
|
1821
1833
|
* untouched, so the historical record of the prior failure (and its
|
|
1822
1834
|
* response status / body) is preserved.
|
|
@@ -1827,27 +1839,27 @@ declare class WebhookEvents {
|
|
|
1827
1839
|
* delivery's outcome to remain on the record.
|
|
1828
1840
|
*
|
|
1829
1841
|
* **Outbound delivery semantics**: the gateway POSTs the clone with
|
|
1830
|
-
* `Idempotency-Key: resend_<
|
|
1831
|
-
* of the source event, not the clone). Recipient handlers that key off
|
|
1842
|
+
* `Idempotency-Key: resend_<cloneUuid>`. Recipient handlers that key off
|
|
1832
1843
|
* `Idempotency-Key` will see this as a distinct delivery from the
|
|
1833
1844
|
* original — distinguishable both by the `resend_` prefix and by reading
|
|
1834
1845
|
* the response payload's `manualResendOf` field.
|
|
1835
1846
|
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
1847
|
+
* The SDK also attaches an `X-Idempotency-Key` header (UUIDv4 unless you
|
|
1848
|
+
* pass `idempotencyKey`); the gateway does not currently deduplicate
|
|
1849
|
+
* `/resend` calls against it, so retrying this call from your own code
|
|
1850
|
+
* after a network failure can create more than one clone — pair it with
|
|
1851
|
+
* your own retry-suppression if that matters for your integration.
|
|
1840
1852
|
*
|
|
1841
|
-
* Returns the *clone* event (new
|
|
1853
|
+
* Returns the *clone* event (new uuid), not the original. The original is
|
|
1842
1854
|
* unchanged on the server.
|
|
1843
1855
|
*
|
|
1844
1856
|
* @example
|
|
1845
|
-
* const event = await garu.webhookEvents.get(
|
|
1846
|
-
* const clone = await garu.webhookEvents.resend(
|
|
1847
|
-
* clone.
|
|
1848
|
-
* clone.manualResendOf === event.
|
|
1857
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1858
|
+
* const clone = await garu.webhookEvents.resend(event.uuid);
|
|
1859
|
+
* clone.uuid !== event.uuid; // true — clone has its own uuid
|
|
1860
|
+
* clone.manualResendOf === event.uuid; // true — points back at the source
|
|
1849
1861
|
*/
|
|
1850
|
-
resend(
|
|
1862
|
+
resend(uuid: string, params?: ResendWebhookEventParams): Promise<WebhookEvent>;
|
|
1851
1863
|
}
|
|
1852
1864
|
|
|
1853
1865
|
interface GaruOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -770,9 +770,14 @@ interface WebhookEventEndpoint {
|
|
|
770
770
|
events: string[];
|
|
771
771
|
[key: string]: unknown;
|
|
772
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Public API v1 webhook-event representation. Keyed on `uuid` — there is no
|
|
775
|
+
* numeric id in this shape. `webhookEndpoint.id` stays numeric: endpoint
|
|
776
|
+
* *configuration* (create/update/delete) is still dashboard-only and did
|
|
777
|
+
* not move to `/api/v1`.
|
|
778
|
+
*/
|
|
773
779
|
interface WebhookEvent {
|
|
774
|
-
|
|
775
|
-
endpointId: number;
|
|
780
|
+
uuid: string;
|
|
776
781
|
/** Eager-loaded endpoint snapshot. */
|
|
777
782
|
webhookEndpoint: WebhookEventEndpoint;
|
|
778
783
|
/** Garu event type, e.g. `transaction.payment.paid`. */
|
|
@@ -791,17 +796,24 @@ interface WebhookEvent {
|
|
|
791
796
|
/** Response body from the most recent attempt, truncated by the gateway. */
|
|
792
797
|
responseBody: string | null;
|
|
793
798
|
/**
|
|
794
|
-
* When this row is a clone produced by `webhookEvents.resend(
|
|
795
|
-
* the
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
+
* When this row is a clone produced by `webhookEvents.resend(uuid)`, this
|
|
800
|
+
* is the uuid of the original event the clone was forked from. `null` on
|
|
801
|
+
* every originally-fired event (and on events resurrected via the legacy
|
|
802
|
+
* `webhookEvents.retry(uuid)` mutation, which mutates in place instead of
|
|
803
|
+
* cloning).
|
|
799
804
|
*/
|
|
800
|
-
manualResendOf:
|
|
805
|
+
manualResendOf: string | null;
|
|
801
806
|
createdAt: string;
|
|
802
807
|
[key: string]: unknown;
|
|
803
808
|
}
|
|
804
|
-
|
|
809
|
+
interface WebhookEventList {
|
|
810
|
+
data: WebhookEvent[];
|
|
811
|
+
/** Items on this page. */
|
|
812
|
+
count: number;
|
|
813
|
+
/** Total matches across all pages. */
|
|
814
|
+
totalCount: number;
|
|
815
|
+
totalPages: number;
|
|
816
|
+
}
|
|
805
817
|
interface ListWebhookEventsParams {
|
|
806
818
|
page?: number;
|
|
807
819
|
limit?: number;
|
|
@@ -1754,7 +1766,8 @@ declare class ScheduledCharges {
|
|
|
1754
1766
|
/**
|
|
1755
1767
|
* Webhook events — the seller-facing delivery log for outbound webhooks.
|
|
1756
1768
|
*
|
|
1757
|
-
*
|
|
1769
|
+
* Backed by `/api/v1/webhook-events`, keyed on `uuid`. Every time the
|
|
1770
|
+
* gateway fires a webhook (e.g. `transaction.payment.paid`,
|
|
1758
1771
|
* `scheduled_charge.cycle_failed`), it persists one row per destination
|
|
1759
1772
|
* endpoint with the full payload, the HTTP outcome, and the retry schedule.
|
|
1760
1773
|
* Use this resource to audit deliveries from the seller's API key — the
|
|
@@ -1762,6 +1775,7 @@ declare class ScheduledCharges {
|
|
|
1762
1775
|
*
|
|
1763
1776
|
* Webhook endpoint *configuration* (URL, subscribed events, secret) is still
|
|
1764
1777
|
* dashboard-only — this resource only covers the event log + manual retries.
|
|
1778
|
+
* `webhookEndpoint.id` on every event stays a numeric id for that reason.
|
|
1765
1779
|
*/
|
|
1766
1780
|
declare class WebhookEvents {
|
|
1767
1781
|
private readonly http;
|
|
@@ -1784,16 +1798,14 @@ declare class WebhookEvents {
|
|
|
1784
1798
|
*/
|
|
1785
1799
|
list(params?: ListWebhookEventsParams): Promise<WebhookEventList>;
|
|
1786
1800
|
/**
|
|
1787
|
-
* Fetch one webhook event by
|
|
1801
|
+
* Fetch one webhook event by uuid — includes the full payload, the
|
|
1788
1802
|
* embedded endpoint snapshot, and the most recent response status/body.
|
|
1789
1803
|
*
|
|
1790
1804
|
* @example
|
|
1791
|
-
* const event = await garu.webhookEvents.get(
|
|
1792
|
-
*
|
|
1793
|
-
* console.log(event.responseStatus, event.responseBody);
|
|
1794
|
-
* }
|
|
1805
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1806
|
+
* event.status === 'failed' && event.responseStatus;
|
|
1795
1807
|
*/
|
|
1796
|
-
get(
|
|
1808
|
+
get(uuid: string): Promise<WebhookEvent>;
|
|
1797
1809
|
/**
|
|
1798
1810
|
* @deprecated For most cases prefer {@link resend}, which preserves the
|
|
1799
1811
|
* original event's audit trail by cloning rather than mutating. `retry()`
|
|
@@ -1802,21 +1814,21 @@ declare class WebhookEvents {
|
|
|
1802
1814
|
* explicitly want the legacy in-place semantics (and for backwards
|
|
1803
1815
|
* compatibility with older CLI / MCP releases).
|
|
1804
1816
|
*
|
|
1805
|
-
* Re-deliver a webhook event by
|
|
1817
|
+
* Re-deliver a webhook event by uuid. Resets it to `pending`, clears the
|
|
1806
1818
|
* retry schedule, and triggers an immediate delivery attempt. Works on
|
|
1807
1819
|
* any status (`success`, `failed`, `pending`).
|
|
1808
1820
|
*
|
|
1809
1821
|
* @example
|
|
1810
1822
|
* const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
1811
1823
|
* for (const event of failed.data) {
|
|
1812
|
-
* await garu.webhookEvents.retry(event.
|
|
1824
|
+
* await garu.webhookEvents.retry(event.uuid);
|
|
1813
1825
|
* }
|
|
1814
1826
|
*/
|
|
1815
|
-
retry(
|
|
1827
|
+
retry(uuid: string): Promise<WebhookEvent>;
|
|
1816
1828
|
/**
|
|
1817
|
-
* Re-deliver a webhook event by
|
|
1829
|
+
* Re-deliver a webhook event by uuid, audit-trail preserving. Unlike
|
|
1818
1830
|
* {@link retry}, this does *not* mutate the original row — it inserts a
|
|
1819
|
-
* fresh event (new
|
|
1831
|
+
* fresh event (new uuid) that points back at the source via
|
|
1820
1832
|
* `manualResendOf`, then dispatches that clone. The original row is
|
|
1821
1833
|
* untouched, so the historical record of the prior failure (and its
|
|
1822
1834
|
* response status / body) is preserved.
|
|
@@ -1827,27 +1839,27 @@ declare class WebhookEvents {
|
|
|
1827
1839
|
* delivery's outcome to remain on the record.
|
|
1828
1840
|
*
|
|
1829
1841
|
* **Outbound delivery semantics**: the gateway POSTs the clone with
|
|
1830
|
-
* `Idempotency-Key: resend_<
|
|
1831
|
-
* of the source event, not the clone). Recipient handlers that key off
|
|
1842
|
+
* `Idempotency-Key: resend_<cloneUuid>`. Recipient handlers that key off
|
|
1832
1843
|
* `Idempotency-Key` will see this as a distinct delivery from the
|
|
1833
1844
|
* original — distinguishable both by the `resend_` prefix and by reading
|
|
1834
1845
|
* the response payload's `manualResendOf` field.
|
|
1835
1846
|
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
1847
|
+
* The SDK also attaches an `X-Idempotency-Key` header (UUIDv4 unless you
|
|
1848
|
+
* pass `idempotencyKey`); the gateway does not currently deduplicate
|
|
1849
|
+
* `/resend` calls against it, so retrying this call from your own code
|
|
1850
|
+
* after a network failure can create more than one clone — pair it with
|
|
1851
|
+
* your own retry-suppression if that matters for your integration.
|
|
1840
1852
|
*
|
|
1841
|
-
* Returns the *clone* event (new
|
|
1853
|
+
* Returns the *clone* event (new uuid), not the original. The original is
|
|
1842
1854
|
* unchanged on the server.
|
|
1843
1855
|
*
|
|
1844
1856
|
* @example
|
|
1845
|
-
* const event = await garu.webhookEvents.get(
|
|
1846
|
-
* const clone = await garu.webhookEvents.resend(
|
|
1847
|
-
* clone.
|
|
1848
|
-
* clone.manualResendOf === event.
|
|
1857
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1858
|
+
* const clone = await garu.webhookEvents.resend(event.uuid);
|
|
1859
|
+
* clone.uuid !== event.uuid; // true — clone has its own uuid
|
|
1860
|
+
* clone.manualResendOf === event.uuid; // true — points back at the source
|
|
1849
1861
|
*/
|
|
1850
|
-
resend(
|
|
1862
|
+
resend(uuid: string, params?: ResendWebhookEventParams): Promise<WebhookEvent>;
|
|
1851
1863
|
}
|
|
1852
1864
|
|
|
1853
1865
|
interface GaruOptions {
|
package/dist/index.js
CHANGED
|
@@ -1287,42 +1287,31 @@ var WebhookEvents = class {
|
|
|
1287
1287
|
* });
|
|
1288
1288
|
*/
|
|
1289
1289
|
async list(params = {}) {
|
|
1290
|
-
const
|
|
1291
|
-
if (params.page !== void 0)
|
|
1292
|
-
if (params.limit !== void 0)
|
|
1293
|
-
if (params.status)
|
|
1294
|
-
if (params.eventType)
|
|
1295
|
-
if (params.endpointId !== void 0)
|
|
1296
|
-
const
|
|
1297
|
-
const url = `/api/webhook-events${
|
|
1298
|
-
|
|
1290
|
+
const query = {};
|
|
1291
|
+
if (params.page !== void 0) query.page = String(params.page);
|
|
1292
|
+
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1293
|
+
if (params.status) query.status = params.status;
|
|
1294
|
+
if (params.eventType) query.eventType = params.eventType;
|
|
1295
|
+
if (params.endpointId !== void 0) query.endpointId = String(params.endpointId);
|
|
1296
|
+
const qs = new URLSearchParams(query).toString();
|
|
1297
|
+
const url = `/api/v1/webhook-events${qs ? `?${qs}` : ""}`;
|
|
1298
|
+
return this.http.call(
|
|
1299
1299
|
(signal) => this.http.client.GET(url, { signal }).then(
|
|
1300
1300
|
(r) => r
|
|
1301
1301
|
)
|
|
1302
1302
|
);
|
|
1303
|
-
return {
|
|
1304
|
-
data: raw.events,
|
|
1305
|
-
meta: {
|
|
1306
|
-
page: raw.page,
|
|
1307
|
-
limit: raw.limit,
|
|
1308
|
-
total: raw.total,
|
|
1309
|
-
totalPages: raw.pages
|
|
1310
|
-
}
|
|
1311
|
-
};
|
|
1312
1303
|
}
|
|
1313
1304
|
/**
|
|
1314
|
-
* Fetch one webhook event by
|
|
1305
|
+
* Fetch one webhook event by uuid — includes the full payload, the
|
|
1315
1306
|
* embedded endpoint snapshot, and the most recent response status/body.
|
|
1316
1307
|
*
|
|
1317
1308
|
* @example
|
|
1318
|
-
* const event = await garu.webhookEvents.get(
|
|
1319
|
-
*
|
|
1320
|
-
* console.log(event.responseStatus, event.responseBody);
|
|
1321
|
-
* }
|
|
1309
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1310
|
+
* event.status === 'failed' && event.responseStatus;
|
|
1322
1311
|
*/
|
|
1323
|
-
async get(
|
|
1312
|
+
async get(uuid) {
|
|
1324
1313
|
return this.http.call(
|
|
1325
|
-
(signal) => this.http.client.GET(`/api/webhook-events/${
|
|
1314
|
+
(signal) => this.http.client.GET(`/api/v1/webhook-events/${uuid}`, { signal }).then(
|
|
1326
1315
|
(r) => r
|
|
1327
1316
|
)
|
|
1328
1317
|
);
|
|
@@ -1335,28 +1324,28 @@ var WebhookEvents = class {
|
|
|
1335
1324
|
* explicitly want the legacy in-place semantics (and for backwards
|
|
1336
1325
|
* compatibility with older CLI / MCP releases).
|
|
1337
1326
|
*
|
|
1338
|
-
* Re-deliver a webhook event by
|
|
1327
|
+
* Re-deliver a webhook event by uuid. Resets it to `pending`, clears the
|
|
1339
1328
|
* retry schedule, and triggers an immediate delivery attempt. Works on
|
|
1340
1329
|
* any status (`success`, `failed`, `pending`).
|
|
1341
1330
|
*
|
|
1342
1331
|
* @example
|
|
1343
1332
|
* const failed = await garu.webhookEvents.list({ status: 'failed', limit: 5 });
|
|
1344
1333
|
* for (const event of failed.data) {
|
|
1345
|
-
* await garu.webhookEvents.retry(event.
|
|
1334
|
+
* await garu.webhookEvents.retry(event.uuid);
|
|
1346
1335
|
* }
|
|
1347
1336
|
*/
|
|
1348
|
-
async retry(
|
|
1337
|
+
async retry(uuid) {
|
|
1349
1338
|
return this.http.call(
|
|
1350
|
-
(signal) => this.http.client.POST(`/api/webhook-events/${
|
|
1339
|
+
(signal) => this.http.client.POST(`/api/v1/webhook-events/${uuid}/retry`, {
|
|
1351
1340
|
body: {},
|
|
1352
1341
|
signal
|
|
1353
1342
|
}).then((r) => r)
|
|
1354
1343
|
);
|
|
1355
1344
|
}
|
|
1356
1345
|
/**
|
|
1357
|
-
* Re-deliver a webhook event by
|
|
1346
|
+
* Re-deliver a webhook event by uuid, audit-trail preserving. Unlike
|
|
1358
1347
|
* {@link retry}, this does *not* mutate the original row — it inserts a
|
|
1359
|
-
* fresh event (new
|
|
1348
|
+
* fresh event (new uuid) that points back at the source via
|
|
1360
1349
|
* `manualResendOf`, then dispatches that clone. The original row is
|
|
1361
1350
|
* untouched, so the historical record of the prior failure (and its
|
|
1362
1351
|
* response status / body) is preserved.
|
|
@@ -1367,30 +1356,30 @@ var WebhookEvents = class {
|
|
|
1367
1356
|
* delivery's outcome to remain on the record.
|
|
1368
1357
|
*
|
|
1369
1358
|
* **Outbound delivery semantics**: the gateway POSTs the clone with
|
|
1370
|
-
* `Idempotency-Key: resend_<
|
|
1371
|
-
* of the source event, not the clone). Recipient handlers that key off
|
|
1359
|
+
* `Idempotency-Key: resend_<cloneUuid>`. Recipient handlers that key off
|
|
1372
1360
|
* `Idempotency-Key` will see this as a distinct delivery from the
|
|
1373
1361
|
* original — distinguishable both by the `resend_` prefix and by reading
|
|
1374
1362
|
* the response payload's `manualResendOf` field.
|
|
1375
1363
|
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
1364
|
+
* The SDK also attaches an `X-Idempotency-Key` header (UUIDv4 unless you
|
|
1365
|
+
* pass `idempotencyKey`); the gateway does not currently deduplicate
|
|
1366
|
+
* `/resend` calls against it, so retrying this call from your own code
|
|
1367
|
+
* after a network failure can create more than one clone — pair it with
|
|
1368
|
+
* your own retry-suppression if that matters for your integration.
|
|
1380
1369
|
*
|
|
1381
|
-
* Returns the *clone* event (new
|
|
1370
|
+
* Returns the *clone* event (new uuid), not the original. The original is
|
|
1382
1371
|
* unchanged on the server.
|
|
1383
1372
|
*
|
|
1384
1373
|
* @example
|
|
1385
|
-
* const event = await garu.webhookEvents.get(
|
|
1386
|
-
* const clone = await garu.webhookEvents.resend(
|
|
1387
|
-
* clone.
|
|
1388
|
-
* clone.manualResendOf === event.
|
|
1374
|
+
* const event = await garu.webhookEvents.get('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
1375
|
+
* const clone = await garu.webhookEvents.resend(event.uuid);
|
|
1376
|
+
* clone.uuid !== event.uuid; // true — clone has its own uuid
|
|
1377
|
+
* clone.manualResendOf === event.uuid; // true — points back at the source
|
|
1389
1378
|
*/
|
|
1390
|
-
async resend(
|
|
1379
|
+
async resend(uuid, params = {}) {
|
|
1391
1380
|
const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
|
|
1392
1381
|
return this.http.call(
|
|
1393
|
-
(signal) => this.http.client.POST(`/api/webhook-events/${
|
|
1382
|
+
(signal) => this.http.client.POST(`/api/v1/webhook-events/${uuid}/resend`, {
|
|
1394
1383
|
body: {},
|
|
1395
1384
|
headers: { "X-Idempotency-Key": idempotencyKey },
|
|
1396
1385
|
signal
|