Webhooks send an HTTP POST to your endpoint whenever something changes in a project — a flag toggled, a rule edited, a rollout step completed.
Create an endpoint
Go to Project settings → Webhooks → Add endpoint, or use the API. Choose the events you want:
flag.updated— state, rules or variations changedflag.created,flag.deletedrollout.step— a scheduled rollout advancedrollout.guard_triggered— a guard paused or rolled back a rollout
Payload
POST /your/webhook
{
"id": "evt_01J9ZK4W3T",
"type": "flag.updated",
"createdAt": "2026-10-01T08:12:44Z",
"environment": "production",
"data": {
"flag": "new-checkout",
"changes": [{ "path": "rollout.percent", "from": 25, "to": 50 }],
"actor": { "type": "user", "email": "mia@acme.dev" }
}
}Verify signatures
Every request carries a Shoal-Signature header: an HMAC-SHA256 of the raw body with your endpoint secret. Reject requests that don’t match.
verify.ts
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(body: string, header: string, secret: string) {
const expected = createHmac("sha256", secret).update(body).digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}verify.py
import hmac, hashlib
def verify(body: bytes, header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)