source defines how Trigger.dev verifies requests and types the event every subscriber receives. Choose a named provider source or supply a verification configuration with webhooks.custom().
Presets
Presets supply the verification configuration, and most also carry the provider’s part of the endpoint’s setup prompt. Set the endpoint’s signing secret or public key as described in Connect a provider.stripe(), github(), svix(), standardWebhooks(), square(), and discord().
Svix and Standard Webhooks
svix() and standardWebhooks() use HMAC-SHA256 over id.timestamp.body with a base64-encoded whsec_ secret. Their header names differ:
Named sources such as
webhooks.clerk() and webhooks.composio() select the corresponding configuration.
Named providers
Each function below returns a source with its provider’s verification configuration. Call it throughwebhooks, for example webhooks.calCom().
Provider IDs containing a hyphen use a camel case function name: the
cal-com provider is webhooks.calCom().
Supabase database webhooks aren’t signed, so supabase() checks a shared secret instead. Generate the endpoint’s secret on Trigger.dev, then add an Authorization header with the value Bearer <secret> under the webhook’s HTTP Headers in Supabase.
Slack also ships as a chat channel in @trigger.dev/slack.
For a complete project built on resend(), see the Resend email agent example. It drafts replies to a Resend inbox and waits for your approval in Slack before sending them.
Hookdeck
hookdeck() verifies requests that a Hookdeck connection forwards to the endpoint. Hookdeck forwards the original provider’s body unchanged, so pass that provider’s event type:
/trigger/stripe-via-hookdeck.ts
- Secret rotation: when you roll the signing secret in Hookdeck with an expiry, Hookdeck also signs each request with the previous secret in
X-Hookdeck-Signature-2, so deliveries keep verifying until you store the new secret. - Deduplication: retries dedupe on
X-Hookdeck-Eventid, which is the same on every attempt of a Hookdeck event. - Custom header prefix: if you changed the header prefix in the Hookdeck project’s settings, pass it with
webhooks.hookdeck({ headerPrefix: "x-acme" }). The prefix renames the event id header; the signature headers keep theX-Hookdeck-name.
Endpoint validation
Some sources also define a response for the provider’s endpoint-validation request. These requests don’t create deliveries or task runs.discord() answers a verified { type: 0 } PING with HTTP 204 and no body. It also returns 204 for accepted events and 401 for invalid signatures. Set the Discord application’s public key as the endpoint’s verification credential.
Slack’s url_verification challenge is handled the same way by @trigger.dev/slack.
whatsapp() answers Meta’s GET verification request when hub.mode is subscribe and hub.verify_token matches the endpoint’s verify token. It returns hub.challenge as text. The verify token is separate from the App Secret used to verify event signatures; see Verify a WhatsApp endpoint URL. Endpoints without GET verification return 405 to GET requests.
Custom providers
webhooks.custom() accepts a verification configuration. This source verifies an HMAC-SHA256 signature over the raw body in x-webhook-signature and uses the event’s id for deduplication:
/trigger/internal.ts
setupPrompt is the provider-specific part of the endpoint’s setup prompt: where the provider’s webhook settings are and how to register a URL there. Trigger.dev adds the URL, the subscribers’ filters and the signing secret steps around it.
Form-encoded bodies
A verified body sent asapplication/x-www-form-urlencoded reaches subscribers as an object of its fields, so filters, chat.event keys and waiter match paths read form fields the way they read JSON fields. A repeated field becomes an array of its values. Slack slash commands and other providers that post forms work this way.
By default an accepted request gets a 200 with a small JSON receipt. Some providers show the response body to the user who triggered the request, so pass response: { acceptedBody: "empty" } to answer with an empty 200 instead:
/trigger/forms.ts
Typing the event
Stripe and GitHub sources provide default event shapes; other sources default tounknown. Pass an event type to the source function for typed handler parameters and autocomplete. This example uses Stripe.Event from the stripe package, which must be installed in your project:
/trigger/stripe.ts
webhooks.custom<T>(), pass your own event type as T. The endpoint’s event type flows to every subscriber: webhook() handlers, chat.event keys and filters, and waiter match paths are all checked against it.
Event types are compile-time annotations. Signature verification doesn’t validate the body against
a TypeScript type. Validate
event inside onEvent if your handler needs runtime schema checks.Verification schemes
Requests must pass verification before they reach any subscriber. Sources can check a signature or credential, enforce a timestamp tolerance, and derive an idempotency key for deduplication. Verification failures return the source’s rejected HTTP status (400 by default).
Custom sources support these schemes:

