Webhooks
Nines sends a signed JSON POST to your endpoint whenever an incident is created, updated, or resolved. Use webhooks to route alerts to Slack, PagerDuty, or any custom system.
Configuring a webhook
- Go to Settings → Notifications → Add channel → Webhook.
- Enter the destination URL.
- Optionally enter a signing secret. When set, every request includes an
X-Webhook-Signatureheader so you can verify authenticity. - Save the channel.
Webhook formats
When configuring a webhook channel, you can choose how Nines formats the request body. Set the format field in the channel configuration to one of:
generic(default) — a JSON object containing all incident fields. Use this for custom integrations and general-purpose HTTP endpoints. See the payload schema below.discord— a Discord-compatible Incoming Webhook payload using an embed with colour-coded status, monitor details, and a link to the incident. Point this at a Discord channel webhook URL.slack— a Slack Block Kit payload with a header block, status fields, and an optional link to the incident. Point this at a Slack Incoming Webhook URL.custom— the body is rendered from a Gotext/templatestring that you supply in thetemplatefield of the channel configuration. The template receives anIncidentContextvalue exposing.Incident,.Monitor,.Org,.Event,.AffectedRegions, and.BaseURL. Use this when you need a completely custom payload shape.
Request format
Nines sends an HTTP POST with the following headers:
Content-Type: application/json
X-Webhook-Signature: sha256=<hex-digest> (only when a secret is configured)
Signing and verification
When you configure a signing secret, Nines computes an HMAC-SHA256 over the raw request body using your secret as the key and includes the result as X-Webhook-Signature: sha256=<hex-digest>.
To verify on your end:
// Pseudocode
expected := "sha256=" + hex(hmac_sha256(secret, request_body))
if not constant_time_equal(expected, request.header["X-Webhook-Signature"]):
reject(401)
Always use a constant-time comparison to prevent timing attacks.
Retry behavior
If your endpoint returns a non-2xx status or the request fails with a network error, Nines retries the delivery up to 3 times with exponential backoff:
- Attempt 1: immediate
- Attempt 2: 1 second delay
- Attempt 3: 2 second delay
After 3 failed attempts the delivery is abandoned and an error is logged. Make your endpoint idempotent — Nines may deliver the same event more than once during retries.
Payload schema
Every webhook payload shares a common top-level shape:
{
"event": string, // "incident.created" | "incident.updated" | "incident.resolved"
"incident": object, // incident fields (see below)
"monitor": object, // the monitor that triggered the incident
"org_name": string, // display name of your organisation
"org_slug": string, // URL slug of your organisation
"affected_regions": [string], // region codes currently reporting down (empty for burn-rate)
"timestamp": string // RFC 3339 UTC timestamp
}
The incident object fields:
{
"id": string, // ULID
"monitor_id": string, // ULID of the parent monitor
"status": string, // "investigating" | "identified" | "resolved"
"details": string, // human-readable description
"started_at": string, // RFC 3339 UTC
"resolved_at": string | null, // RFC 3339 UTC, null while open
"created_at": string, // RFC 3339 UTC
"updated_at": string, // RFC 3339 UTC
"sli_type": string | null // "availability_burn" | "latency_burn" | null for region failures
}