Workflow status changed
This is the HTTP POST request Halliday sends to your registered url when a workflow
reaches a terminal state — it is not an endpoint you call. Respond with any 2xx within the
10-second timeout to acknowledge; anything else (or a timeout) is treated as a failed delivery
and retried.
Verifying the signature
Each delivery carries an X-Halliday-Signature header: a comma-separated list of v1=0x<hex>
values, where each <hex> is HMAC-SHA256(raw_body) computed with an active signing secret
(used as a UTF-8 string), prefixed with 0x. During a secret rotation more than one signature
is present — treat the request as valid if any entry matches. Always verify against the
raw request body, before JSON parsing.
If you configured an auth_header when registering the webhook, Halliday also includes that
custom header on every delivery — check it alongside the signature.
const crypto = require("crypto");
function verifyHallidaySignature(rawBody, headerValue, signingSecret) {
const expected = crypto
.createHmac("sha256", signingSecret) // secret used as UTF-8 string
.update(rawBody)
.digest("hex");
return headerValue
.split(",")
.map((s) => s.trim().replace(/^v1=/, "").replace(/^0x/, ""))
.some((sig) =>
sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
);
}
Delivery & retry semantics
- Acknowledgement: any
2xxresponse within the 10-second timeout. - Retries: up to 12 attempts within a 24-hour window, after which the delivery is marked
FAILED. - Backoff: exponential with jitter — roughly 1m, 5m, 15m, 1h, 2h, 4h, then 8h between attempts.
- Idempotency: a given
(workflow_id, webhook, event_type)is enqueued once. De-duplicate on the deliveryid, since a retried delivery reuses the sameid.
Headers
Comma-separated list of v1=0x<hex> HMAC-SHA256 signatures over the raw request body.
Body
The signed JSON payload Halliday POSTs to your receiver URL.
Unique delivery id. Use it for idempotency — a retried delivery reuses the same id.
"9555b9ed-1d0c-47ad-9e41-056fb4fe087e"
ISO-8601 timestamp of the event.
"2026-06-22T18:04:11.000Z"
Event type a webhook can subscribe to. WORKFLOW_COMPLETED fires when a workflow's status
becomes COMPLETE; WORKFLOW_FAILED fires when it becomes FAILED.
WORKFLOW_COMPLETED, WORKFLOW_FAILED The terminal workflow state.
Response
Return any 2xx to acknowledge receipt. Any other status — or no response within 10
seconds — is treated as a failed delivery and retried.

