Skip to content

feat: add webhook delivery retry - #42

Merged
bjarn merged 2 commits into
mainfrom
feat/webhook-delivery-retry
Oct 19, 2026
Merged

bjarn merged 2 commits into
mainfrom
feat/webhook-delivery-retry

Conversation

@bjarn

@bjarn bjarn commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds webhooks.deliveries.retry(webhookId, deliveryId, options?), which sends a webhook delivery's original payload to the webhook again now. The retry counts as a delivery attempt; if it fails with a retryable error, automatic retries continue. Team token.

  • Lives next to webhooks.deliveries.retrieve(webhookId, deliveryId), following the SDK's existing webhooks.deliveries.* grouping.
  • Sends no request body and no Idempotency-Key (the operation takes none). Takes the usual RequestOptions.
  • Returns RetryWebhookDeliveryResponse ({ message, delivery_id }, HTTP 202).
  • A 409 (WEBHOOK_DISABLED, WEBHOOK_DELIVERY_NOT_RETRYABLE, WEBHOOK_DELIVERY_RETRY_IN_PROGRESS) throws the existing ConflictError (an ApiError) with the code in error.code. No new error class.
  • Empty, . and .. path parameters are rejected before any request, as for the other methods.
  • README: the method is listed in the Team API table and the Team API example.

Non-breaking. Suggested bump: minor.

API changes in the regenerated types

Change Where SDK impact
New operation POST /webhooks/{webhookId}/deliveries/{deliveryId}/retry (team token, no body, 202) operations.ts, new RetryWebhookDeliveryResponse type New method webhooks.deliveries.retry
next_retry_at?: string | null: when the next automatic retry is due, null when none is scheduled WebhookDeliveryData, WebhookDeliveryListData Optional field added to response types; no code change
payload, response_body, response_headers, error_message now document that they are always included with a team API token WebhookDeliveryData Doc comments only; types unchanged
401/403/429 error bodies listed as either ErrorMessage ({ message }) or ApiError ({ error: { code, message } }); 429 is inline instead of the shared TooManyRequests response webhook delivery list/get, retry, regenerate-secret None: the error parser already reads both shapes (covered by the transport tests)
Spec pin and team spec hash in the generated headers types.ts, operations.ts None

Usage

import { ConflictError, Lettermint } from 'lettermint';

const lettermint = new Lettermint({ teamToken: process.env.LETTERMINT_TEAM_TOKEN });

try {
  const { delivery_id } = await lettermint.webhooks.deliveries.retry('webhook-id', 'delivery-id');
} catch (error) {
  if (error instanceof ConflictError) console.log(error.code); // e.g. WEBHOOK_DELIVERY_NOT_RETRYABLE
}

const delivery = await lettermint.webhooks.deliveries.retrieve('webhook-id', 'delivery-id');
console.log(delivery.next_retry_at); // ISO 8601 string, or null when no automatic retry is scheduled

Checks

Run locally on Node v26.5.0:

Command Result
npm ci ok
npm run generate regenerated types.ts and operations.ts only
npm run generate:check up to date
npm run lint ok, 33 files
npm run type-check ok
npm run test:coverage 8 suites, 324 tests passed; 97.45% statements, 91.79% branches
npm run build ok
npm run test:smoke packed, ESM import, CJS require and type declarations ok
npx jest on Node v23.2.0 324 tests passed

New tests in test/team-api.test.ts: operation coverage (now 60 operations), path, method, team auth header, no body and no Idempotency-Key; 202 parsed into RetryWebhookDeliveryResponse; 409 WEBHOOK_DELIVERY_NOT_RETRYABLE as ConflictError with its code; path-parameter validation for both IDs; next_retry_at read as a value and as null on a delivery and on a delivery list.

Not run locally

  • The CI matrix on Node 20, 22 and 24: only Node 26 and 23 are installed here.

Suggested release tag

v3.2.0, together with the unreleased messages.resend and per-email batch idempotency keys already on main since v3.1.0.

🤖 Generated with Claude Code

bjarn and others added 2 commits October 18, 2026 22:51
- New team operation POST /webhooks/{webhookId}/deliveries/{deliveryId}/retry
  returning RetryWebhookDeliveryResponse (202).
- WebhookDeliveryData and WebhookDeliveryListData gain optional, nullable
  next_retry_at.
- WebhookDeliveryData content fields note that they are always included with
  a team API token.
- Webhook delivery endpoints and regenerate-secret list 401/403/429 bodies as
  either ErrorMessage or ApiError.

Co-Authored-By: Claude <noreply@anthropic.com>
Add webhooks.deliveries.retry(webhookId, deliveryId, options?), which
sends a delivery's original payload to the webhook again. Team token.

Co-Authored-By: Claude <noreply@anthropic.com>
@bjarn
bjarn requested a review from a team as a code owner October 18, 2026 20:55
@bjarn
bjarn merged commit 6d89407 into main Oct 19, 2026
4 checks passed
@bjarn
bjarn deleted the feat/webhook-delivery-retry branch October 19, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants