@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 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(42);
401
- console.log(event.responseStatus, event.responseBody);
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(42);
405
- clone.id !== event.id; // true — fresh row with its own id
406
- clone.manualResendOf === event.id; // true — points back at the source
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(id)` is the audit-preserving counterpart to `retry(id)` — 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
+ `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_<originalId>`, 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
+ 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 qs = new URLSearchParams();
1297
- if (params.page !== void 0) qs.set("page", String(params.page));
1298
- if (params.limit !== void 0) qs.set("limit", String(params.limit));
1299
- if (params.status) qs.set("status", params.status);
1300
- if (params.eventType) qs.set("event_type", params.eventType);
1301
- if (params.endpointId !== void 0) qs.set("endpoint_id", String(params.endpointId));
1302
- const query = qs.toString();
1303
- const url = `/api/webhook-events${query ? `?${query}` : ""}`;
1304
- const raw = await this.http.call(
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 numeric ID — includes the full payload, the
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(42);
1325
- * if (event.status === 'failed') {
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(id) {
1318
+ async get(uuid) {
1330
1319
  return this.http.call(
1331
- (signal) => this.http.client.GET(`/api/webhook-events/${id}`, { signal }).then(
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 ID. Resets it to `pending`, clears the
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.id);
1340
+ * await garu.webhookEvents.retry(event.uuid);
1352
1341
  * }
1353
1342
  */
1354
- async retry(id) {
1343
+ async retry(uuid) {
1355
1344
  return this.http.call(
1356
- (signal) => this.http.client.POST(`/api/webhook-events/${id}/retry`, {
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 ID, audit-trail preserving. Unlike
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 numeric id) that points back at the source via
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_<originalId>` (where `<originalId>` is the id
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
- * **SDK→gateway dedup**: the SDK auto-attaches `X-Idempotency-Key`
1383
- * (UUIDv4 unless you pass `idempotencyKey`) so transient transport
1384
- * retries (5xx SDK backoff) cannot create duplicate clones the
1385
- * backend returns the original clone on the second call within 24h.
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 id), not the original. The original is
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(42);
1392
- * const clone = await garu.webhookEvents.resend(42);
1393
- * clone.id !== event.id; // true — clone has its own id
1394
- * clone.manualResendOf === event.id; // true — points back at the source
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(id, params = {}) {
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/${id}/resend`, {
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
- id: number;
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(id)`, this is
795
- * the numeric id of the original event the clone was forked from. `null`
796
- * on every originally-fired event (and on events resurrected via the
797
- * legacy `webhookEvents.retry(id)` mutation, which mutates in place
798
- * instead of cloning).
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: number | null;
805
+ manualResendOf: string | null;
801
806
  createdAt: string;
802
807
  [key: string]: unknown;
803
808
  }
804
- type WebhookEventList = PaginatedList<WebhookEvent>;
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
- * Every time the gateway fires a webhook (e.g. `transaction.payment.paid`,
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 numeric ID — includes the full payload, the
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(42);
1792
- * if (event.status === 'failed') {
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(id: number): Promise<WebhookEvent>;
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 ID. Resets it to `pending`, clears the
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.id);
1824
+ * await garu.webhookEvents.retry(event.uuid);
1813
1825
  * }
1814
1826
  */
1815
- retry(id: number): Promise<WebhookEvent>;
1827
+ retry(uuid: string): Promise<WebhookEvent>;
1816
1828
  /**
1817
- * Re-deliver a webhook event by ID, audit-trail preserving. Unlike
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 numeric id) that points back at the source via
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_<originalId>` (where `<originalId>` is the id
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
- * **SDK→gateway dedup**: the SDK auto-attaches `X-Idempotency-Key`
1837
- * (UUIDv4 unless you pass `idempotencyKey`) so transient transport
1838
- * retries (5xx SDK backoff) cannot create duplicate clones the
1839
- * backend returns the original clone on the second call within 24h.
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 id), not the original. The original is
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(42);
1846
- * const clone = await garu.webhookEvents.resend(42);
1847
- * clone.id !== event.id; // true — clone has its own id
1848
- * clone.manualResendOf === event.id; // true — points back at the source
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(id: number, params?: ResendWebhookEventParams): Promise<WebhookEvent>;
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
- id: number;
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(id)`, this is
795
- * the numeric id of the original event the clone was forked from. `null`
796
- * on every originally-fired event (and on events resurrected via the
797
- * legacy `webhookEvents.retry(id)` mutation, which mutates in place
798
- * instead of cloning).
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: number | null;
805
+ manualResendOf: string | null;
801
806
  createdAt: string;
802
807
  [key: string]: unknown;
803
808
  }
804
- type WebhookEventList = PaginatedList<WebhookEvent>;
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
- * Every time the gateway fires a webhook (e.g. `transaction.payment.paid`,
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 numeric ID — includes the full payload, the
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(42);
1792
- * if (event.status === 'failed') {
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(id: number): Promise<WebhookEvent>;
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 ID. Resets it to `pending`, clears the
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.id);
1824
+ * await garu.webhookEvents.retry(event.uuid);
1813
1825
  * }
1814
1826
  */
1815
- retry(id: number): Promise<WebhookEvent>;
1827
+ retry(uuid: string): Promise<WebhookEvent>;
1816
1828
  /**
1817
- * Re-deliver a webhook event by ID, audit-trail preserving. Unlike
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 numeric id) that points back at the source via
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_<originalId>` (where `<originalId>` is the id
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
- * **SDK→gateway dedup**: the SDK auto-attaches `X-Idempotency-Key`
1837
- * (UUIDv4 unless you pass `idempotencyKey`) so transient transport
1838
- * retries (5xx SDK backoff) cannot create duplicate clones the
1839
- * backend returns the original clone on the second call within 24h.
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 id), not the original. The original is
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(42);
1846
- * const clone = await garu.webhookEvents.resend(42);
1847
- * clone.id !== event.id; // true — clone has its own id
1848
- * clone.manualResendOf === event.id; // true — points back at the source
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(id: number, params?: ResendWebhookEventParams): Promise<WebhookEvent>;
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 qs = new URLSearchParams();
1291
- if (params.page !== void 0) qs.set("page", String(params.page));
1292
- if (params.limit !== void 0) qs.set("limit", String(params.limit));
1293
- if (params.status) qs.set("status", params.status);
1294
- if (params.eventType) qs.set("event_type", params.eventType);
1295
- if (params.endpointId !== void 0) qs.set("endpoint_id", String(params.endpointId));
1296
- const query = qs.toString();
1297
- const url = `/api/webhook-events${query ? `?${query}` : ""}`;
1298
- const raw = await this.http.call(
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 numeric ID — includes the full payload, the
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(42);
1319
- * if (event.status === 'failed') {
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(id) {
1312
+ async get(uuid) {
1324
1313
  return this.http.call(
1325
- (signal) => this.http.client.GET(`/api/webhook-events/${id}`, { signal }).then(
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 ID. Resets it to `pending`, clears the
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.id);
1334
+ * await garu.webhookEvents.retry(event.uuid);
1346
1335
  * }
1347
1336
  */
1348
- async retry(id) {
1337
+ async retry(uuid) {
1349
1338
  return this.http.call(
1350
- (signal) => this.http.client.POST(`/api/webhook-events/${id}/retry`, {
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 ID, audit-trail preserving. Unlike
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 numeric id) that points back at the source via
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_<originalId>` (where `<originalId>` is the id
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
- * **SDK→gateway dedup**: the SDK auto-attaches `X-Idempotency-Key`
1377
- * (UUIDv4 unless you pass `idempotencyKey`) so transient transport
1378
- * retries (5xx SDK backoff) cannot create duplicate clones the
1379
- * backend returns the original clone on the second call within 24h.
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 id), not the original. The original is
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(42);
1386
- * const clone = await garu.webhookEvents.resend(42);
1387
- * clone.id !== event.id; // true — clone has its own id
1388
- * clone.manualResendOf === event.id; // true — points back at the source
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(id, params = {}) {
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/${id}/resend`, {
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Official Node.js / TypeScript SDK for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",