Ignitify.dev
Trigger from a webhook
Guides

Trigger from a webhook

A webhook starts a run when another system sends a signed HTTP call. Create one with hook:create, and get a callback when runs end with notify:set.

1 · Create the webhook

hook:create needs the deployment id and the task to run, and its reply shows the secret once, so store it now.

terminal
$ ignitify hook:create dep_Hn4TqXw8Zc2P --task-name image-resize⚠️  The `secret` below is shown ONCE and cannot be read back — `hook:list` never returns it. Store it now; if it is lost, delete the hook and create a new one.A webhook body over 10 KiB is refused with 413 before the signature is checked.✓ Webhook Createdresource_id          hok_Wd3Lm8Qz5RtYhook_id              4f1c9a7e2b6d03581a9c7e4d2f60b8315ce79a04d1b2863furl                  https://api.ignitify.dev/hooks/trigger/4f1c9a7e2b6d03581a9c7e4d2f60b8315ce79a04d1b2863fsecret (shown ONCE)  9d3f6a1c8e5b2074a6c91f3e8d0b5a72c4e61f98b3d7a05e2c4f1a86d09b37e

2 · Sign the body and send it

The signature is the HMAC-SHA256 of the exact body, in hex, with the secret as the key.

sender
SECRET=9d3f6a1c8e5b2074a6c91f3e8d0b5a72c4e61f98b3d7a05e2c4f1a86d09b37e
HOOK_URL=https://api.ignitify.dev/hooks/trigger/4f1c9a7e2b6d03581a9c7e4d2f60b8315ce79a04d1b2863f
BODY='{"name":"world"}'

SIG=$(printf %s "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')

# x-ignitify-delivery is optional: a repeated id returns the same run.
curl -X POST "$HOOK_URL" \
  -H "content-type: application/json" \
  -H "x-ignitify-signature: sha256=$SIG" \
  -H "x-ignitify-delivery: order-1042" \
  -d "$BODY"

3 · Read the answer

A good request answers 202 and starts a run whose payload is the body text.

answers
202  {"run_id":"019fdec4-2b71-7d90-a3c5-1e8f4b6a9d02","resource_id":"run_Qm3TbX8kLw2Z","status":"PENDING"}
401  {"error":"invalid signature"}
404  {"error":"unknown hook"}
413  {"error":"payload too large"}
429  {"error":"rate limited"}

4 · List and delete webhooks

hook:list shows the webhooks of a deployment, and hook:delete removes one by its own hok_ id.

terminal
$ ignitify hook:list dep_Hn4TqXw8Zc2Pid           019f3c30-6e12-7b44-8a07-9c15d3e2f8a6resource_id  hok_Wd3Lm8Qz5RtYhook_id      4f1c9a7e2b6d03581a9c7e4d2f60b8315ce79a04d1b2863ftask_name    image-resizecreated_at   2026-10-14T09:40:00.000Z

5 · Get a callback when a run ends

notify:set takes an HTTPS URL and a signing secret of at least 32 characters, read from stdin. The URL is your own endpoint, and the server must be able to find its host name.

terminal
$ printf %s "$NOTIFY_SECRET" | ignitify notify:set dep_Hn4TqXw8Zc2P --url https://your-domain.example/ignitify --secret-stdinNotify URL for dep_Hn4TqXw8Zc2P set to https://your-domain.example/ignitify

6 · Check the callback signature

The callback is a POST with the same x-ignitify-signature header, so check it the same way.

receiver.ts
import { createHmac, timingSafeEqual } from "node:crypto";

// Body: {"run_id":"run_Qm3TbX8kLw2Z","status":"COMPLETED","deployment_id":"…","tenant_id":"…"}
export function isFromIgnitify(rawBody: string, header: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const got = header.replace(/^sha256=/, "");
  return got.length === expected.length && timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}