|
1 | 1 | --- |
2 | 2 | title: "Trigger tasks from Hookdeck webhooks" |
3 | 3 | sidebarTitle: "Hookdeck webhooks" |
4 | | -description: "This example demonstrates how to use Hookdeck to receive webhooks and trigger Trigger.dev tasks." |
| 4 | +description: "Forward webhooks from a Hookdeck connection to a hosted Trigger.dev endpoint, verified with the Hookdeck project's signing secret, and run a task for each event." |
5 | 5 | --- |
6 | 6 |
|
7 | | -## Overview |
| 7 | +[Hookdeck](https://hookdeck.com) receives webhooks from external services, then queues, logs and forwards them to a destination. Point a Hookdeck connection at a hosted webhook endpoint and Trigger.dev verifies each forwarded request with the Hookdeck project's signing secret, deduplicates Hookdeck's retries, and runs your task with the original provider's payload. |
8 | 8 |
|
9 | | -This example shows how to use [Hookdeck](https://hookdeck.com) as your webhook infrastructure to trigger Trigger.dev tasks. Hookdeck receives webhooks from external services, and forwards them directly to the Trigger.dev API. This gives you the best of both worlds: Hookdeck's webhook management, logging, and replay capabilities, combined with Trigger.dev's reliable task execution. |
| 9 | +## Task code |
| 10 | + |
| 11 | +Declare the endpoint with `webhooks.hookdeck()` and subscribe a task to it. Hookdeck forwards the original provider's body unchanged, so pass that provider's event type. This example relays Stripe events: |
| 12 | + |
| 13 | +```ts /trigger/stripe-via-hookdeck.ts |
| 14 | +import type Stripe from "stripe"; |
| 15 | +import { webhook, webhooks } from "@trigger.dev/sdk"; |
| 16 | + |
| 17 | +export const stripeViaHookdeck = webhooks.endpoint.define({ |
| 18 | + id: "stripe-via-hookdeck", |
| 19 | + source: webhooks.hookdeck<Stripe.Event>(), |
| 20 | +}); |
| 21 | + |
| 22 | +export const paymentSucceeded = webhook({ |
| 23 | + id: "payment-succeeded", |
| 24 | + endpoint: stripeViaHookdeck, |
| 25 | + filter: "event.type == 'payment_intent.succeeded'", |
| 26 | + onEvent: async ({ event }) => { |
| 27 | + console.log("Payment succeeded", event.id); |
| 28 | + }, |
| 29 | +}); |
| 30 | +``` |
10 | 31 |
|
11 | | -## Key features |
| 32 | +Run `trigger dev` or deploy, then copy the endpoint's URL from the Webhooks page in the dashboard. |
12 | 33 |
|
13 | | -- Use Hookdeck as your webhook endpoint for external services |
14 | | -- Hookdeck forwards webhooks directly to Trigger.dev tasks via the API |
15 | | -- All webhooks are logged and replayable in Hookdeck |
| 34 | +## Set up Hookdeck |
16 | 35 |
|
17 | | -## Setting up Hookdeck |
| 36 | +<Steps> |
| 37 | + <Step title="Create a connection"> |
| 38 | + In the [Hookdeck dashboard](https://dashboard.hookdeck.com), create a [connection](https://hookdeck.com/docs/connections) from your source (for example a Stripe source) to an HTTP destination whose URL is the endpoint's URL. Keep the destination's authentication on **Hookdeck Signature**, the default for new destinations: Hookdeck only signs forwarded requests with it set. |
| 39 | + </Step> |
| 40 | + <Step title="Store the signing secret"> |
| 41 | + Copy the signing secret from **Settings > Secrets** in Hookdeck and set it as the endpoint's signing secret in the Trigger.dev dashboard. It's one secret for the whole Hookdeck project. |
| 42 | + </Step> |
| 43 | +</Steps> |
18 | 44 |
|
19 | | -You'll configure everything in the [Hookdeck dashboard](https://dashboard.hookdeck.com). No code changes needed in your app. |
| 45 | +## Test it |
20 | 46 |
|
21 | | -### 1. Create a destination |
| 47 | +Send a webhook to your Hookdeck source URL, or trigger a real event in the upstream provider. In Hookdeck, the event shows a `200` response from the destination. In Trigger.dev, the endpoint shows a succeeded delivery and the `payment-succeeded` task has a completed run with the Stripe event as its payload. |
22 | 48 |
|
23 | | -In Hookdeck, create a new [destination](https://hookdeck.com/docs/destinations) with the following settings: |
| 49 | +A request signed with a different secret gets a `400`, which Hookdeck reports as a failed attempt. |
24 | 50 |
|
25 | | -- **URL**: `https://api.trigger.dev/api/v1/tasks/<task-id>/trigger` (replace `<task-id>` with your task ID) |
26 | | -- **Method**: POST |
27 | | -- **Authentication**: Bearer token (create a named **Trigger only** environment API key and use it as `TRIGGER_SECRET_KEY`) |
| 51 | +## Rotate the signing secret |
28 | 52 |
|
29 | | -### 2. Add a transformation |
| 53 | +Roll the signing secret under **Settings > Secrets** in Hookdeck with an expiry instead of expiring it immediately. Until the old secret expires, Hookdeck signs each request with both secrets, sending the previous secret's signature in `X-Hookdeck-Signature-2`. The endpoint accepts either, so deliveries keep verifying while you copy the new secret to Trigger.dev. Set a grace period when you store it to keep accepting the old secret for a while. |
30 | 54 |
|
31 | | -Create a [transformation](https://hookdeck.com/docs/transformations) to wrap the webhook body in the `payload` field that Trigger.dev expects: |
| 55 | +## Deduplication |
32 | 56 |
|
33 | | -```javascript |
34 | | -addHandler("transform", (request, context) => { |
35 | | - request.body = { payload: { ...request.body } }; |
36 | | - return request; |
| 57 | +Hookdeck retries and manual replays of the same event carry the same `X-Hookdeck-Eventid`, and the endpoint uses it as the [deduplication](/webhooks/deliveries#deduplication) key, so a retried event runs your task once. |
| 58 | + |
| 59 | +If you changed the header prefix in the Hookdeck project's settings, the event id arrives under the new prefix. Pass the prefix so deduplication keeps working: |
| 60 | + |
| 61 | +```ts /trigger/stripe-via-hookdeck.ts |
| 62 | +import type Stripe from "stripe"; |
| 63 | +import { webhooks } from "@trigger.dev/sdk"; |
| 64 | + |
| 65 | +export const stripeViaHookdeck = webhooks.endpoint.define({ |
| 66 | + id: "stripe-via-hookdeck", |
| 67 | + source: webhooks.hookdeck<Stripe.Event>({ headerPrefix: "x-acme" }), |
37 | 68 | }); |
38 | 69 | ``` |
39 | 70 |
|
40 | | -### 3. Create a connection |
| 71 | +The signature headers keep the `X-Hookdeck-` name whatever the prefix. |
41 | 72 |
|
42 | | -Create a [connection](https://hookdeck.com/docs/connections) that links your source (where webhooks come from) to the destination and transformation you created above. |
| 73 | +## Trigger a task through the API instead |
43 | 74 |
|
44 | | -## Task code |
| 75 | +You can also point a Hookdeck destination at the [trigger task API](/management/tasks/trigger) without a hosted endpoint. Hookdeck authenticates with your API key instead of a signature, and a transformation wraps the body in the `payload` field the API expects. |
| 76 | + |
| 77 | +1. Create a destination with the URL `https://api.trigger.dev/api/v1/tasks/<task-id>/trigger`, method `POST`, and **Bearer token** authentication using a **Trigger only** environment API key. |
| 78 | +2. Add a [transformation](https://hookdeck.com/docs/transformations): |
45 | 79 |
|
46 | | -This task will be triggered when Hookdeck forwards a webhook to the Trigger.dev API. |
| 80 | + ```javascript |
| 81 | + addHandler("transform", (request, context) => { |
| 82 | + request.body = { payload: { ...request.body } }; |
| 83 | + return request; |
| 84 | + }); |
| 85 | + ``` |
47 | 86 |
|
48 | | -```ts trigger/webhook-handler.ts |
| 87 | +3. Create a connection from your source to that destination and transformation. |
| 88 | + |
| 89 | +```ts /trigger/webhook-handler.ts |
49 | 90 | import { task } from "@trigger.dev/sdk"; |
50 | 91 |
|
51 | 92 | export const webhookHandler = task({ |
52 | 93 | id: "webhook-handler", |
53 | 94 | run: async (payload: Record<string, unknown>) => { |
54 | | - // The payload contains the original webhook data from the external service |
55 | 95 | console.log("Received webhook:", payload); |
56 | | - |
57 | | - // Add your custom logic here |
58 | 96 | }, |
59 | 97 | }); |
60 | 98 | ``` |
61 | 99 |
|
62 | | -## Testing your setup |
63 | | - |
64 | | -To test everything is working: |
65 | | - |
66 | | -1. Set up your destination, transformation, and connection in [Hookdeck](https://dashboard.hookdeck.com) |
67 | | -2. Send a test webhook to your Hookdeck source URL (use the Hookdeck Console or cURL) |
68 | | -3. Check the Hookdeck dashboard to verify the webhook was received and forwarded |
69 | | -4. Check the [Trigger.dev dashboard](https://cloud.trigger.dev) to see the successful run of your task |
| 100 | +This path has no deduplication of Hookdeck retries; each forwarded request triggers a run. |
70 | 101 |
|
71 | | -For more information on setting up Hookdeck, refer to the [Hookdeck Documentation](https://hookdeck.com/docs). |
| 102 | +For more on Hookdeck, see the [Hookdeck documentation](https://hookdeck.com/docs). |
0 commit comments