Webhooks
Outbound webhooks POST to your endpoint whenever Izri emits an event for one of your organization's projects. Every attempt is logged.
Event types
Three, currently:
| Event | Fires when |
|---|---|
delta_report.updated |
The aggregate verdict for a delta changed. |
scope_check.completed |
A scope analysis finished. |
test_run.completed |
A test run reached a terminal status. |
delta_report.updated is the one most integrations want — it is the umbrella verdict changing, which is the thing worth reacting to.
A subscription with an empty event list receives all events. Listing events explicitly narrows it.
There is no finding.created. Findings are JSONB arrays on check rows rather than first-class entities, so there is no clean emit point for them yet.
Verifying the signature
Every request carries an HMAC over the exact bytes posted, in the x-izri-signature-256 header, formatted sha256=<hex>. Same scheme as GitHub's.
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(rawBody: string, header: string, secret: string): boolean {
const expected = `sha256=${createHmac('sha256', secret).update(rawBody).digest('hex')}`
const a = Buffer.from(expected)
const b = Buffer.from(header)
return a.length === b.length && timingSafeEqual(a, b)
}Two things to get right:
- Sign the raw body, not a re-serialized object.
JSON.parsefollowed byJSON.stringifycan reorder keys or change whitespace, and the HMAC won't match. Capture the raw bytes before any body parser runs. - Compare in constant time.
===on a signature leaks timing.
Retries
An attempt that doesn't succeed is retried with exponential backoff, starting at 2 seconds and doubling: 2s, 4s, 8s, 16s, 32s, up to 5 attempts. After that the delivery is marked failed.
A subscription that fails 10 consecutive times is disabled to stop Izri hammering a dead endpoint indefinitely. Re-enable it from the dashboard once your endpoint is healthy.
Make your handler idempotent
Retries mean your endpoint will occasionally receive the same event twice — a delivery that timed out after your handler committed still counts as a failure and gets retried. Key on the delta or run identifier in the payload and make reprocessing a no-op.
Respond fast
Acknowledge with a 2xx as soon as you've persisted the payload, then do the real work asynchronously. A slow handler burns through the retry budget on work that already succeeded.
Related
- Signals overview — what a verdict change actually means.
- REST API — the rest of the HTTP surface.
Reading this with an agent? /docs/configure/webhooks.md serves the raw markdown.
Edit this page on GitHub →All docs