Skip to content

Webhooks push events out of Firefight as they happen, so your systems react in real time instead of polling the REST API. Wire them into status pages, ticketing systems, data warehouses, or anything else that should know when an incident moves.

Go to Settings → Webhooks and add a webhook with a name, a destination URL, and the events it should receive. Managing webhooks requires workspace admin access. The URL must use http or https, and it must be publicly reachable. Deliveries to addresses that resolve to private networks are refused.

Each webhook gets its own signing secret, generated when you create it. Open the webhook’s detail panel to reveal the secret and to browse its recent deliveries. You can also send a test delivery from settings, which replays a recent matching event from your workspace against your endpoint.

You choose the events per webhook. A webhook only receives what it subscribes to.

EventFires when
incident.createdAn incident is declared
incident.updatedAn incident’s core fields change
incident.resolvedAn incident is resolved
incident.reopenedA closed incident is reopened
incident.escalatedAn incident is escalated
incident.marked_duplicateAn incident is marked as a duplicate
incident.merged_intoAn incident is merged into another
lead.assignedAn incident lead is assigned
EventFires when
action.createdAn action item is created
action.picked_upSomeone picks up an action item
action.completedAn action item is completed
EventFires when
runbook.attachedA runbook attaches to an incident
runbook.appliedA runbook’s steps are turned into action items
EventFires when
postmortem.generatedA postmortem is generated for an incident
EventFires when
relationship.createdAn incident is linked to a related incident

Firefight sends each event as an HTTP POST with a JSON body and the User-Agent Firefight-Webhooks/1.0. Your endpoint has 7 seconds to respond. Any 2xx response counts as success, and anything else, including timeouts and connection errors, counts as failure.

Every request carries these headers.

HeaderContents
X-Webhook-VersionPayload schema version, currently 1
X-Webhook-EventThe event type, for example incident.resolved
X-Webhook-DeliveryUnique ID of this delivery
X-Webhook-AttemptAttempt counter for this delivery
X-Webhook-TimestampISO 8601 time the request was signed
X-Webhook-SignatureSignature in the form v1=<hex digest>

Failed deliveries are not retried automatically. Each webhook keeps a delivery history in Settings → Webhooks showing the state, response code, and payload of every attempt from the last 7 days, and you can replay any delivery from there. A replayed delivery reuses the exact original payload bytes, so its signature still verifies.

If a webhook fails 10 times in a row over the span of an hour or more, Firefight deactivates it so a dead endpoint does not accumulate failures forever. Fix the endpoint, then re-enable the webhook in Settings → Webhooks. Any successful delivery resets the failure counter.

Every payload shares the same envelope, with event-specific detail under data. This is an incident.created delivery.

{
"id": "3c8e5f2a-9b1d-4e7c-a6f0-8d2b4c6e9a13",
"version": "1",
"event_type": "incident.created",
"workspace_id": "7a1c3e5b-2d4f-4a68-9c0e-1b3d5f7a9c2e",
"occurred_at": "2026-07-18T09:12:44Z",
"data": {
"incident": {
"id": "0d9b2c1e-7f3a-4b8e-9c5d-2a6e8f1b4d70",
"identifier": "INC-42",
"name": "Checkout latency spike in eu-west",
"summary": "p99 latency on the checkout service exceeded 4s.",
"status": { "id": "b1f6a2d4-8c3e-4f5a-9b7d-1e2c3a4b5d6f", "name": "Investigating", "lifecycle_stage": "active" },
"severity": { "id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "name": "SEV2", "rank": 2 },
"type": null,
"lead": null,
"source": "datadog",
"declared_by": { "id": "e4a8b2c6-1d3f-4e5a-b7c9-0f1a2b3c4d5e", "type": "user", "name": "Maja Kovac", "email": "maja@example.com" },
"declared_at": "2026-07-18T09:12:44Z",
"detected_at": null,
"resolved_at": null,
"created_at": "2026-07-18T09:12:44Z",
"updated_at": "2026-07-18T09:12:44Z",
"custom_fields": {},
"channel_id": "C0912345678",
"channel_name": "inc-42-checkout-latency-spike"
},
"actor": { "id": "e4a8b2c6-1d3f-4e5a-b7c9-0f1a2b3c4d5e", "type": "user", "name": "Maja Kovac", "email": "maja@example.com" }
}
}

The actor is whoever caused the event. Its type is user for a person and api_key for an integration, in which case email is null. Action, postmortem, and relationship events carry their own detail under data alongside the incident.

Every delivery is signed with the webhook’s secret using HMAC-SHA256. The signed input is the scheme, the timestamp, and the raw body joined with colons.

v1:<X-Webhook-Timestamp>:<raw request body>

To verify, compute the HMAC-SHA256 hex digest of that string with your signing secret and compare it against the digest in X-Webhook-Signature using a constant-time comparison. Reject the delivery if it does not match.

const crypto = require("crypto")
function verify(secret, timestamp, rawBody, signatureHeader) {
const expected = "v1=" + crypto
.createHmac("sha256", secret)
.update(`v1:${timestamp}:${rawBody}`)
.digest("hex")
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
}