Browse docs
Docs /configure/webhooks
Configure

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.parse followed by JSON.stringify can 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.

Reading this with an agent? /docs/configure/webhooks.md serves the raw markdown.

Edit this page on GitHub →All docs