Webhook Notifications
Route Durabull alert events to HTTPS webhook endpoints with signed JSON payloads.
Webhook notifications let alert rules POST structured JSON to any HTTPS endpoint you control. Use them for custom paging, automation (Zapier, n8n), internal incident systems, or middleware that forwards alerts into Slack or PagerDuty.
Setup
You can configure webhooks in two ways:
- Saved webhook destinations: reusable organization-level endpoints managed from settings.
- Custom webhook URLs: one-off endpoints configured directly on an alert rule.
For reusable destinations:
- Open Settings → Integrations.
- Add a Webhook alert destination with a name and endpoint URL.
- Optionally add a signing secret (minimum 16 characters).
- Use Test to verify delivery.
- Open a connection's alert rule builder and choose the saved destination from a Webhook route.
For one-off endpoints, open a connection's alert rule builder, add a Webhook route, switch it to Custom URL, and enter the endpoint URL and optional signing secret.
Webhook routes are configured per alert rule, alongside email and Linear destinations. Saved destination edits apply to future alert deliveries only; deliveries already queued use the URL and signing secret snapshot captured when the alert was enqueued.
Payload format
Durabull sends versioned JSON with schemaVersion: 1.
{
"schemaVersion": 1,
"event": "alert.fired",
"id": "alert-event-uuid",
"deliveryId": "delivery-uuid",
"occurredAt": "2026-05-25T12:00:00.000Z",
"organization": { "id": "org_123", "slug": "acme" },
"connection": { "id": "conn_123", "name": "Production Redis" },
"rule": { "id": "rule_123", "name": "High failure rate", "type": "failure_rate" },
"queue": { "name": "email-send" },
"alert": {
"status": "firing",
"summary": "Failure rate exceeded threshold",
"context": { "jobId": "42", "failedReason": "SMTP timeout" },
"firedAt": "2026-05-25T12:00:00.000Z",
"dedupeKey": null
},
"links": {
"dashboard": "https://app.durabull.io/acme/c/conn_123/queues/email-send",
"job": "https://app.durabull.io/acme/c/conn_123/queues/email-send/jobs/42",
"muteRule": "https://app.durabull.io/acme/c/conn_123/alerts?ruleId=rule_123"
}
}
Test deliveries use event: "alert.test" with synthetic context.
Durabull does not include full BullMQ job.data payloads in webhook bodies.
Request headers
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | Durabull-Alerts/1.0 |
Idempotency-Key | Alert event id — use to dedupe retries |
X-Durabull-Delivery-Id | Delivery attempt id |
X-Durabull-Timestamp | Unix seconds (when signing is enabled) |
X-Durabull-Signature | sha256=<hex> HMAC (when signing is enabled) |
Verifying signatures
When a signing secret is configured, verify:
signature = HMAC-SHA256(secret, "{timestamp}.{rawBody}")
Reject requests older than five minutes to limit replay attacks.
import { createHmac, timingSafeEqual } from 'node:crypto'
function verifyDurabullWebhook(rawBody: string, headers: Headers, secret: string): boolean {
const timestamp = headers.get('x-durabull-timestamp')
const signature = headers.get('x-durabull-signature')
if (!timestamp || !signature) return false
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false
const expected = createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex')
const provided = signature.replace(/^sha256=/, '')
return timingSafeEqual(Buffer.from(provided), Buffer.from(expected))
}
Delivery behavior
- Durabull uses at-least-once delivery with exponential backoff retries.
- Respond with any
2xxstatus to acknowledge receipt. 408,429, and5xxresponses are retried.- Most other
4xxresponses are treated as permanent failures. - Requests time out after 10 seconds.
- Due retry attempts are swept by the existing alert monitor, so retries can continue even after the original alert is no longer actively firing.
- Retry attempts stop after 7 days from the first delivery enqueue. The delivery row is marked permanently failed so dead endpoints do not retry forever.
Security notes
- Production webhook URLs must use HTTPS.
- Durabull blocks private and localhost targets (SSRF protection).
- Saved destination signing secrets are encrypted at rest and masked in API responses.
- Custom per-rule webhook signing secrets remain scoped to that alert rule and are masked in API responses after save.
For local development only, set DURABULL_WEBHOOK_ALLOW_HTTP=true to permit HTTP webhook URLs.