Trigger.dev v4.8.0

Hosted webhooks, plus Slack and Linear agents for chat.agent.

3 new features, 5 improvements, and 12 server changes.

Highlights

Hosted webhooks

Declare a webhook endpoint once and Trigger.dev hosts its URL, verifies every request against the provider's signature, and delivers each event to the tasks and agents subscribed to it. Subscribe a task with webhook() and a type-safe filter:


import { webhook, webhooks } from "@trigger.dev/sdk";
export const stripe = webhooks.endpoint.define({
id: "stripe",
source: webhooks.stripe(),
});
export const fulfill = webhook({
id: "fulfill",
endpoint: stripe,
filter: "event.type == 'checkout.session.completed'",
onEvent: async ({ event }) => {
// fulfill the order
},
});

To pause a run until a matching event arrives, create a waiter and wait on it:


const waiter = await webhooks.waiter.create(stripe, {
match: { "event.data.object.metadata.orderId": order.id },
});
const { event } = await webhooks.waiter.wait(waiter).unwrap();

Sources cover Stripe, GitHub, Clerk, Shopify, Svix, Discord, Hookdeck and more, and webhooks.custom<T>(config) handles any other provider. Retries are deduplicated on the provider's own event or delivery ID, and every delivery can be inspected and replayed from the dashboard or the API. Agents can subscribe to the same endpoint: chat.event({ endpoint, key }) routes events into an agent session, and chat.channels.custom({ endpoint }) connects any chat surface.

Webhooks docs

Slack agents

@trigger.dev/slack turns a chat.agent into a native Slack agent. Each DM or channel thread is a durable session: the reply streams into the thread with the turn's tool calls shown as a plan, approvals are Approve and Deny buttons, and Slack's stop button stops the turn.


import { webhooks } from "@trigger.dev/sdk";
import { chat } from "@trigger.dev/sdk/ai";
import { appMentions, slack, webhookSource } from "@trigger.dev/slack";
import { anthropic } from "@ai-sdk/anthropic";
const slackEvents = webhooks.endpoint.define({
id: "slack",
source: webhookSource(),
});
export const support = chat.agent({
id: "support",
channels: [
slack({
id: "slack",
endpoint: slackEvents,
token: process.env.SLACK_BOT_TOKEN!,
startOn: appMentions(),
}),
],
run: async ({ messages, signal, streamText }) =>
streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }),
});

startOn decides which channel messages start a session, and appMentions() answers when the agent is @mentioned. Images and PDFs people share reach the model, and messages sent while the agent is answering are folded into the reply.

Slack agents docs

Linear agents

@trigger.dev/linear turns a chat.agent into a Linear agent. Assign it an issue or @mention it, and Linear's agent session becomes a durable Trigger.dev session: the reply posts back to Linear, tool calls show as activities, and approvals are Approve and Deny options that resume the run.


import { webhooks } from "@trigger.dev/sdk";
import { chat } from "@trigger.dev/sdk/ai";
import { linear, webhookSource } from "@trigger.dev/linear";
import { anthropic } from "@ai-sdk/anthropic";
const linearEvents = webhooks.endpoint.define({
id: "linear",
source: webhookSource(),
});
export const triage = chat.agent({
id: "triage",
channels: [
linear({
id: "linear",
endpoint: linearEvents,
token: process.env.LINEAR_ACCESS_TOKEN!,
}),
],
run: async ({ messages, signal, streamText }) =>
streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal }),
});

The first turn gets the issue's context and earlier comments, and images and PDFs in the issue reach the model. linearPlanTool() keeps the plan Linear shows as a checklist up to date, and a Stop in Linear winds the turn down.

Linear agents docs

Improvements

  • Add webhooks.hookdeck(), a source for deliveries relayed through a Hookdeck connection. It verifies x-hookdeck-signature, keeps verifying while the secret is rolled (Hookdeck sends the previous secret's signature in x-hookdeck-signature-2), and deduplicates retries on x-hookdeck-eventid. Pass the original provider's event type, for example webhooks.hookdeck<Stripe.Event>(). (51b39fb)
  • HMAC webhook verifier configs accept additionalSignatureHeaders: more headers that can carry a signature, matched as alternatives to signatureHeader, so providers that send a second signature during a secret rotation keep verifying. (08d1ddb)
  • The generate_webhook_secret and set_webhook_secret MCP tools take an optional previousSecretTtlSeconds to keep accepting the old signing secret while the provider switches to the new one (up to 7 days), and report when the old secret stops working. (98adb66)
  • The streamText passed to a chat.agent's run() now turns AI SDK telemetry on by default, so each model step and tool call shows up as a span in the run trace. With telemetry: { recordUserMessage: false } the spans are kept without prompt and response content. Pass experimental_telemetry: { isEnabled: false } to turn them off. (bd7cc35)
  • Realtime streams now reconnect and resume when the stream backend reports a failed read mid-stream, instead of ending early as if the stream had finished. This affects runs.subscribeToRun with streams, useRealtimeRunWithStreams, and chat streams. (23730b0)

Server changes

These changes are included in the v4.8.0 Docker image and are already live on Trigger.dev Cloud:

  • Rotating a webhook endpoint's signing secret can keep the old one valid for a while, so deliveries still signed with it keep verifying. The rotate and regenerate dialogs let you choose how long (up to 7 days, 24 hours by default), and the rotate-secret and secret endpoints accept previousSecretTtlSeconds and return previousSecretExpiresAt. With no value, the old secret stops working immediately, as before.
  • Runs now get a TRIGGER_DASHBOARD_URL environment variable with the dashboard's address, so a task can link to its own run: ${TRIGGER_DASHBOARD_URL}/runs/${ctx.run.id}. A TRIGGER_DASHBOARD_URL you set on the project takes precedence.
  • Run traces and the trace APIs load faster for older runs.
  • Runs whose deployment has no compute template now go straight to containers when triggered, instead of first passing through the compute worker queue.
  • When regenerating an environment's API key, you can now revoke the previous key immediately instead of keeping it working for 24 hours. Use this when a key may have leaked.
  • The API keys page now always lists your root API key, masked to its last 4 characters when it's hidden, so you can regenerate it and revoke the previous key.
  • Alerts are now checked every minute instead of every 5 to 10 minutes, so they raise and recover sooner.
  • Creating an alert no longer needs the dashboard agent.
  • Small fixes to creating and editing alerts.
  • Alerts sent to Slack channels connected through a removed Slack installation deliver again.
  • Set KUBERNETES_POD_RESERVED_SOURCE_PORTS on the supervisor (for example 50080,50081) to stop runs using those ports for outbound connections, which avoids port clashes on the node.
  • The supervisor no longer trusts certificates issued under the compromised emSign (eMudhra) certificate authorities.

How to upgrade

Update the trigger.dev/* packages to v4.8.0 using your package manager:


npx trigger.dev@latest update # npm
pnpm dlx trigger.dev@latest update # pnpm
yarn dlx trigger.dev@latest update # yarn
bunx trigger.dev@latest update # bun

Self-hosted users: update your Docker image to ghcr.io/triggerdotdev/trigger.dev:v4.8.0.

Deploy your first agent today

Get set up in minutes, either on your own or with your coding agent.

Get started for free