Skip to main content

Webhooks

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Flux POSTs a signed JSON payload to every registered webhook URL when a lifecycle event occurs.

Event types

EventWhen
run.startedA pipeline run begins
run.succeededA run completes without error
run.failedA run exits with a non-zero status
step.failedA step exhausts its retry budget
pipeline.deployedA new version of a pipeline is pushed live

Payload shape

{
"id": "evt_01J8B1Q3VZ9Y7C...",
"type": "run.failed",
"created_at": "2026-04-24T09:14:02Z",
"data": {
"run_id": "01J8AZX4K5PQC3D7X5YJ6V",
"pipeline_id": "orders.ingest",
"error": {
"step": "normalize",
"message": "ZodError: total must be >= 0",
"stack": "..."
}
}
}

Verifying the signature

Flux signs each delivery with HMAC-SHA256 using the secret you provided when registering the webhook. The signature is in the X-Flux-Signature header.

import crypto from 'node:crypto';
import type { IncomingMessage } from 'node:http';

export function verify(req: IncomingMessage, rawBody: Buffer, secret: string) {
const header = req.headers['x-flux-signature'];
if (typeof header !== 'string') return false;

const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(header),
Buffer.from(`sha256=${expected}`),
);
}
Always verify

Unverified webhook handlers are a well-known foot-gun. If you skip the HMAC check, anyone who guesses the URL can replay events into your system.

Retries

Flux retries failed deliveries with exponential back-off up to 24 hours. A delivery is considered successful if the endpoint returns 2xx within 10 seconds.