> ## Documentation Index
> Fetch the complete documentation index at: https://trigger.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks overview

> Receive provider webhooks on hosted, verified endpoints and route each event to tasks, agents, and waiting runs.

**A webhook endpoint is one hosted URL that you register with a provider.** Trigger.dev verifies every request against the endpoint's [source](https://trigger.dev/docs/webhooks/sources.md), records it as a [delivery](https://trigger.dev/docs/webhooks/deliveries.md), and hands the event to everything subscribed to the endpoint.

Declare the endpoint once, then subscribe to it:

```ts /trigger/stripe.ts theme={"theme":"css-variables"}
import { webhook, webhooks } from "@trigger.dev/sdk";

export const stripe = webhooks.endpoint.define({
  id: "stripe",
  source: webhooks.stripe(),
});

export const fulfillOrder = webhook({
  id: "fulfill-order",
  endpoint: stripe,
  filter: "event.type == 'checkout.session.completed'",
  onEvent: async ({ event }) => {
    console.log("Fulfilling", event.data.object.id);
  },
});

export const recordRefund = webhook({
  id: "record-refund",
  endpoint: stripe,
  filter: "event.type == 'charge.refunded'",
  onEvent: async ({ event, headers, endpoint, ctx }) => {
    console.log("Refund", event.id, "on", endpoint?.id, "in run", ctx.run.id);
  },
});
```

Stripe gets one URL. A checkout event runs `fulfill-order`, a refund runs `record-refund`, and anything else is recorded as `FILTERED`.

## What can subscribe

| Subscriber | Declared with | What a delivery does |
| - | - | - |
| Task | `webhook({ endpoint, onEvent })` | Starts a run of the task with the event. |
| Agent session | [`chat.event({ endpoint, key })`](https://trigger.dev/docs/webhooks/session-routing) listed on a `chat.agent` | Delivers an action to the session the `key` names. |
| Chat frontend | a [channel connector](https://trigger.dev/docs/webhooks/channels.md) such as `chat.channels.custom({ endpoint })` | Runs a turn on the conversation's session and posts the reply back. |
| Waiting run | [`webhooks.waiter.create(endpoint, { match })`](https://trigger.dev/docs/webhooks/waiters) | Resumes a run that is waiting for this event. |

Each subscriber has its own [filter](https://trigger.dev/docs/webhooks/filters.md), so one delivery can reach several subscribers and skip the rest. An endpoint can have up to 25 subscribers. An endpoint with no subscribers still gets a URL, so you can register it with the provider before writing the handlers.

## The handler

`onEvent` receives:

| Argument | Value |
| - | - |
| `event` | The verified request body, parsed as JSON. Its TypeScript type comes from the [source](https://trigger.dev/docs/webhooks/sources.md#typing-the-event). |
| `headers` | Request headers as a Web `Headers` object, with case-insensitive `get()` and `has()` methods. Credentials such as signatures are removed. |
| `endpoint` | The endpoint the delivery arrived on: `id`, `declaredId`, `tenantId`, `externalRef`, and the `metadata` you declared. |
| `ctx` | The same [run context](https://trigger.dev/docs/context.md) that regular tasks receive. |

`webhook()` also takes the options a [task](https://trigger.dev/docs/tasks/overview.md) does, such as `queue`, `concurrency`, `machine`, `retry`, `maxDuration` and the lifecycle hooks. For example, to handle one delivery at a time:

```ts theme={"theme":"css-variables"}
export const orders = webhook({
  id: "stripe-orders",
  endpoint: stripe,
  queue: { concurrencyLimit: 1 },
  retry: { maxAttempts: 5 },
  onEvent: async ({ event }) => {
    // ...
  },
});
```

The limit covers every delivery the task handles. To process each customer's events in order while different customers run in parallel, route them to an agent with [session routing](https://trigger.dev/docs/webhooks/session-routing.md): deliveries with the same key land in one session and are handled one after another.

`webhooks.endpoint.define` also takes a `description` and `metadata`. The metadata is passed to every subscriber as `endpoint.metadata`. The endpoint `id` can't start with `wh_`, which is reserved for the ids Trigger.dev generates.

## How it works

The CLI finds your endpoints and subscribers during `trigger dev` and deployment, and each environment gets one endpoint per declared id. The endpoint holds the URL and the credential used to verify requests.

A request must pass verification before anything else happens. Provider handshakes are answered directly and create no delivery. A verified request is checked for duplicates, recorded, and then routed: each subscriber's filter is checked, matching subscribers run, and waiting runs whose match fits the event are resumed. The delivery records a result per subscriber.

## Pricing and limits

Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes are billed like any other run: a per-run invocation cost plus compute time. See [pricing](https://trigger.dev/pricing).

A delivery that no subscriber's filter matches starts no run for any subscriber, so it costs nothing. A run already waiting for that webhook still resumes. A run [waiting](https://trigger.dev/docs/webhooks/waiters.md) for a webhook is suspended, so it uses no compute until the webhook arrives.

Each plan sets limits on the ingest rate, waiting runs, processing concurrency and how long deliveries are kept. See [Limits](https://trigger.dev/docs/limits.md#webhook-ingest-rate-limits).

## Connect it

Every endpoint can produce a setup prompt for an AI coding agent. It holds the URL, the events your subscribers filter on, and the steps for registering the endpoint and its signing secret with the provider. Copy it from the endpoints list or the endpoint's page, or read it with the MCP server's `get_webhook_endpoint_details` tool. See [Connect a provider](https://trigger.dev/docs/webhooks/connect.md).

> [card] [Connect a provider](https://trigger.dev/docs/webhooks/connect.md)
>
> Register the URL and signing secret, then send a test event.

> [card] [Sources and verification](https://trigger.dev/docs/webhooks/sources.md)
>
> Choose a provider source or define a custom verification scheme.

> [card] [Filters](https://trigger.dev/docs/webhooks/filters.md)
>
> Choose which events reach each subscriber.

> [card] [Waiters](https://trigger.dev/docs/webhooks/waiters.md)
>
> Pause a run until a matching webhook arrives.

> [card] [Deliveries and endpoints](https://trigger.dev/docs/webhooks/deliveries.md)
>
> Inspect received events and where each one went.

> [card] [Session routing](https://trigger.dev/docs/webhooks/session-routing.md)
>
> Route deliveries to a durable per-key agent session.

> [card] [Channels](https://trigger.dev/docs/webhooks/channels.md)
>
> Turn a webhook into a chat frontend for an agent.

> [card] [Human-in-the-loop](https://trigger.dev/docs/webhooks/human-in-the-loop.md)
>
> Approvals and interactive controls over a channel.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.