Skip to content

feat(sdk,cli,core): webhook() with typed provider sources, filters, and indexing - #4923

Closed
ericallam wants to merge 1 commit into
mainfrom
feat/hosted-webhooks-sdk
Closed

feat(sdk,cli,core): webhook() with typed provider sources, filters, and indexing#4923
ericallam wants to merge 1 commit into
mainfrom
feat/hosted-webhooks-sdk

Conversation

@ericallam

Copy link
Copy Markdown
Member

Summary

The public SDK half of hosted webhooks, split out of #4537 so the webhook API can ship on its own. webhook() declares an endpoint that routes a verified, typed event to an onEvent handler, with provider presets (webhooks.stripe(), webhooks.github(), webhooks.svix(), and the rest of the config-table producers) or webhooks.custom<T>(), plus an optional filter checked against the event type at author time.

import { webhook, webhooks } from "@trigger.dev/sdk";

export const stripeWebhook = webhook({
  id: "stripe-webhook",
  source: webhooks.stripe(),
  filter: "event.type == 'checkout.session.completed'",
  onEvent: async ({ event, headers, ctx }) => {
    // verified, typed Stripe event
  },
});

The CLI indexes declared webhooks into the worker manifest and fails indexing on duplicate webhook ids with a DuplicateWebhookIdsError. Docs add the Webhooks section: overview, sources, connecting a provider, deliveries, and filters.

Stack

This is the bottom of a two-PR stack. #4537 (chat.event, session routing, channels, human-in-the-loop, @trigger.dev/slack) is retargeted onto this branch and merges after it. The server half (#4344) is already on main behind a flag.

Testing

  • tsc --noEmit clean for @trigger.dev/sdk and trigger.dev (CLI).
  • Full @trigger.dev/sdk vitest suite passes with the stacked branch applied on top.
  • Every internal link in the new docs pages resolves to an existing page.

Changelog

Adds webhook() and webhooks.* provider sources to @trigger.dev/sdk, webhook indexing and duplicate-id detection to the CLI, and the webhooks docs section. One changeset bumps core, sdk, and the CLI together.

🤖 Generated with Claude Code

https://claude.ai/code/session_016PPzBQgFgqD8aPQcEYZXty

…nd indexing

The public SDK half of hosted webhooks: `webhook()` declares an endpoint that
routes a verified, typed event to `onEvent`, with provider presets
(`webhooks.stripe()`, `webhooks.github()`, `webhooks.svix()`, and the rest of
the config-table producers) or `webhooks.custom<T>()`, and an optional
type-checked `filter`. The CLI indexes declared webhooks into the worker
manifest and fails indexing on duplicate webhook ids. Docs cover sources,
connecting a provider, deliveries, and filters.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PPzBQgFgqD8aPQcEYZXty
@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a46f330

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
@trigger.dev/core Minor
@trigger.dev/sdk Minor
trigger.dev Minor
@trigger.dev/build Minor
@trigger.dev/python Minor
@trigger.dev/redis-worker Minor
@trigger.dev/schema-to-json Minor
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/metrics-pipeline Patch
@trigger.dev/rbac Minor
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/run-store Patch
@internal/schedule-engine Patch
@internal/tracing Patch
@internal/webhook-engine Patch
@internal/webhook-sources Patch
@internal/dashboard-agent Patch
@internal/cache Patch
@trigger.dev/react-hooks Minor
@trigger.dev/rsc Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor
@trigger.dev/sso Minor
@internal/testcontainers Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Walkthrough

Adds hosted webhook declarations with typed provider sources, custom verification, filters, event handlers, and webhook metadata. Extends worker indexing and deployment manifests with webhook data and duplicate-ID detection. Adds documentation for webhook sources, provider connection, deliveries, filters, and lifecycle behavior. Adds release metadata for the webhook packages.

Priority: ➖ Normal

Merge Risk: 🟠 High · up to a46f3

Manual webhook triggers can invoke handlers without event data, while duplicate webhook IDs can cause indexing to time out instead of reporting the collision. Fix these paths before merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 9 files. (7 skipped: 7… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main changes: the webhook API, typed provider sources, filters, and CLI indexing.
Description check ✅ Passed The description explains the implementation, testing, changelog, stacked PR context, and documentation changes. It omits the issue-closing line and checklist from the template, but it is otherwise suf…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 9 files. (7 skipped: 7 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hosted-webhooks-sdk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
docs/webhooks/sources.mdx (1)

15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use typescript for all TypeScript fences.

The documentation guide specifies typescript as the TypeScript fence tag. Change the five ts fences in this page to typescript.

packages/trigger-sdk/src/v3/webhooks.ts (1)

294-307: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a type alias for Webhooks.

This follows the repository’s TypeScript convention. The change is type-only and has no runtime effect.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 120ae2de-2a9b-46a2-9c92-c795719cbbb8

📥 Commits

Reviewing files that changed from the base of the PR and between 752573c and a46f330.

📒 Files selected for processing (16)
  • .changeset/hosted-webhook-ingress.md
  • docs/docs.json
  • docs/webhooks/connect.mdx
  • docs/webhooks/deliveries.mdx
  • docs/webhooks/filters.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/sources.mdx
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/indexing/indexWorkerManifest.ts
  • packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts
  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
  • packages/trigger-sdk/src/v3/webhooks.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📜 Review details
⏰ Context from checks skipped due to timeout. (46)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (18, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (16, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (23, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (21, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (24, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (22, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (1, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (10, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (19, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (3, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (7, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (14, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (4, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (17, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (20, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (12, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (13, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (9, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (15, 24)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (11, 24)
  • GitHub Check: e2e / 🧪 CLI v3 tests (warp-windows-latest-x64-8x - pnpm)
  • GitHub Check: sdk-compat / Node.js 26.4 (warp-ubuntu-latest-x64-4x)
  • GitHub Check: e2e / 🧪 CLI v3 tests (warp-windows-latest-x64-8x - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (warp-ubuntu-latest-x64-4x - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (warp-ubuntu-latest-x64-4x - pnpm)
  • GitHub Check: sdk-compat / Node.js 22.23 (warp-ubuntu-latest-x64-4x)
  • GitHub Check: sdk-compat / Node.js 24.18 (warp-ubuntu-latest-x64-4x)
  • GitHub Check: sdk-compat / Node.js 20.20 (warp-ubuntu-latest-x64-4x)
  • GitHub Check: packages / 🧪 Unit Tests: Packages (2, 3)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: runops-guard / runops-guard
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: packages / 🧪 Unit Tests: Packages (3, 3)
  • GitHub Check: packages / 🧪 Unit Tests: Packages (1, 3)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: fk-cascade-guard / fk-cascade-guard
  • GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp (2, 2)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: internal / 🧪 Unit Tests: Internal
  • GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp (1, 2)
  • GitHub Check: code-quality / code-quality
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (12)
**Public packages** (`packages/*`): Use `build`.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
  • packages/cli-v3/src/indexing/indexWorkerManifest.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
Code in `src/entryPoints/` runs inside customer containers and is a different runtime environment from the CLI - changes affect deployed task execution directly

📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)

Files:

  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
Always import from `@trigger.dev/sdk`.

📄 CodeRabbit inference engine (packages/trigger-sdk/CLAUDE.md)

Files:

  • packages/trigger-sdk/src/v3/webhooks.ts
Use zod for validation in packages/core and apps/webapp

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • packages/trigger-sdk/src/v3/webhooks.ts
Never import the root package (`@trigger.dev/core`).

📄 CodeRabbit inference engine (packages/core/CLAUDE.md)

Files:

  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
Dev mode code should be located in `src/dev/` and runs tasks locally in the user's Node.js process without containers

📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)

Files:

  • packages/cli-v3/src/dev/devSupervisor.ts
Main documentation config must be defined in `docs.json` which includes navigation structure, theme, and metadata Navigation structure in `docs.json` should be organized using `navigation.dropdowns` with groups and pages

📄 CodeRabbit inference engine (docs/CLAUDE.md)

Files:

  • docs/docs.json
Use function declarations instead of default exports

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
  • packages/cli-v3/src/indexing/indexWorkerManifest.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format Use Mintlify components for structured content: , , , , ,

📄 CodeRabbit inference engine (docs/CLAUDE.md)

Files:

  • docs/webhooks/connect.mdx
  • docs/webhooks/sources.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/filters.mdx
  • docs/webhooks/deliveries.mdx
Use types over interfaces for TypeScript Avoid using enums; prefer string unions or const objects instead

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
  • packages/cli-v3/src/indexing/indexWorkerManifest.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs Do not use high-cardinality attributes in OTEL metr...

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

Files:

  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/core/src/v3/errors.ts
  • packages/core/src/v3/schemas/messages.ts
  • packages/cli-v3/src/indexing/indexWorkerManifest.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
🧠 Learnings (1)
📚 Learning: 2026-04-30T20:30:29.458Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3226
File: docs/ai-chat/quick-start.mdx:13-13
Timestamp: 2026-04-30T20:30:29.458Z
Learning: In this repo’s documentation MDX files (`docs/**/*.mdx`), use `ts` and `tsx` (not `typescript`) as the code-fence language tags for TypeScript/TSX snippets. Do not flag `ts`/`tsx` code-fence language tags as incorrect in any docs MDX file, since this is the site-wide Mintlify-compatible convention.

Applied to files:

  • docs/webhooks/sources.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/filters.mdx
🪛 LanguageTool
.changeset/hosted-webhook-ingress.md

[uncategorized] ~9-~9: The official name of this software platform is spelled with a capital “H”.
Context: ...rce with a preset (webhooks.stripe(), webhooks.github(), and others) or `webhooks.custom(...

(GITHUB)


[grammar] ~10-~10: Ensure spelling is correct
Context: ... hosted URL on deploy. - filter gates which deliveries run, using a type-safe expre...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/webhooks/sources.mdx

[uncategorized] ~57-~57: The official name of this software platform is spelled with a capital “H”.
Context: ... The available presets are stripe(), github(), svix(), square(), and `discord(...

(GITHUB)

🔇 Additional comments (10)
docs/webhooks/connect.mdx (1)

1-35: LGTM!

packages/trigger-sdk/src/v3/webhooks.ts (1)

1-23: LGTM!

Also applies to: 48-200, 203-232, 252-263, 265-267, 313-330

packages/cli-v3/src/indexing/reportWebhookIdCollisions.ts (1)

1-21: LGTM!

Also applies to: 25-28

packages/cli-v3/src/entryPoints/dev-index-worker.ts (1)

20-20: LGTM!

Also applies to: 204-204

packages/cli-v3/src/entryPoints/managed-index-worker.ts (1)

20-20: LGTM!

Also applies to: 200-200

packages/cli-v3/src/dev/devSupervisor.ts (1)

394-394: LGTM!

packages/core/src/v3/schemas/messages.ts (1)

47-50: LGTM!

packages/core/src/v3/errors.ts (1)

610-639: LGTM!

packages/cli-v3/src/indexing/indexWorkerManifest.ts (1)

4-4: LGTM!

Also applies to: 98-104

packages/cli-v3/src/entryPoints/managed-index-controller.ts (1)

106-106: LGTM!

Comment on lines +22 to +24
Duplicate deliveries are deduplicated automatically. The idempotency key is the provider's event id
(e.g. the Stripe event id, or GitHub's `X-GitHub-Delivery`), so a provider retry of the same event
resolves to the original delivery and won't trigger a second run.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Qualify the duplicate-delivery guarantee.

If a source has no configured idempotency field and a provider retry has a new timestamp or signature, the fallback key changes. internal-packages/webhook-engine/src/engine/verification/derive.ts:3-25 hashes the raw body, timestamp, and signature in that case. The retry can create another delivery and run.

State that automatic retry deduplication requires a stable provider event ID. Tell custom-source users to configure idempotencyField when the provider supplies one.

Comment on lines +22 to +24
async (msg) => {
send(msg);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Await the IPC send completion before exiting.

sendMessageInCatalog awaits its sender, but both callbacks call safeSend(msg) without returning its result. safeSend can skip the send or swallow a synchronous process.send error, so reportWebhookIdCollisions still returns true and the worker exits after 10 ms. The parent can then wait for the 20-second timeout instead of receiving WEBHOOKS_FAILED_TO_INDEX.

Make safeSend return a promise backed by the process.send callback. Reject when the channel is unavailable, process.send throws, or the callback receives an error, and return that promise from both reporter callbacks. The callback confirms that Node wrote to the IPC channel; it does not confirm that the parent processed the message. Add an acknowledgement protocol if that stronger guarantee is required.

Comment on lines +239 to +243
const task = createTask<TIdentifier, InferWebhookEvent<TSource>, void>({
id,
triggerSource: "webhook",
run: async (payload, runOptions) => {
const envelope = payload as unknown as WebhookRunPayload<InferWebhookEvent<TSource>>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not expose event-only trigger methods for this task.

WebhookHandle accepts TEvent through methods such as trigger(). The runner then casts that event to WebhookRunPayload<TEvent> and reads envelope.event.

A call such as handle.trigger(event) therefore type-checks, but onEvent receives undefined. Use the envelope as the internal task input. Return a webhook-specific handle that omits manual trigger methods, or implement manual event handling explicitly.

@ericallam

Copy link
Copy Markdown
Member Author

Closing; this work is being reorganised and will be re-opened separately.

@ericallam ericallam closed this Sep 11, 2026
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.

1 participant