Skip to content

The generic webhook source accepts a POST request with a JSON body from any monitoring tool. You tell Firefight where each field lives in the payload with a configurable mapping, so it covers any tool that can send JSON to a URL.

Go to Settings → Alert Sources and click Add source. Give it a name, pick the Generic webhook provider, and create it. Firefight generates a unique ingest URL and a secret token for this source and opens its setup, where you can copy both. The URL has this shape:

https://<your Firefight host>/api/v1/alerts/<endpoint-path>

The endpoint path is a random identifier unique to this source. Use the exact URL shown in Settings → Alert Sources.

Every request must carry the source’s secret token in one of these ways. Firefight accepts any of them, so use whichever your tool can set.

HeaderFormat
AuthorizationBearer <token>
X-Firefight-Token<token>
AuthorizationHTTP Basic auth with any user name and the token as the password

Requests with a missing or wrong token are rejected with 401. Requests to an unknown or disabled source URL get 404.

With no custom mapping, Firefight reads these top-level keys from the payload:

{
"id": "evt-8271",
"title": "High error rate on checkout",
"description": "5xx rate above 5% for 10 minutes",
"service": "checkout",
"severity": "critical",
"status": "firing",
"environment": "production"
}

Sent with curl:

Terminal window
curl -X POST "https://<your Firefight host>/api/v1/alerts/<endpoint-path>" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"id": "evt-8271",
"title": "High error rate on checkout",
"service": "checkout",
"severity": "critical",
"status": "firing"
}'

A successful request returns a JSON body like {"ok": true, "received": 1, "failed": 0}. A payload where no mapped field resolves is rejected with 422, which tells you the mapping does not fit the payload. Bodies over 512 KB are rejected, and each source is rate limited to 60 alerts per minute, counting every alert in a batch, and returns 429 when exceeded so well-behaved tools retry later. A body that is not valid JSON gets 400.

Edit the source in Settings → Alert Sources to change where each field is read from. A mapping row pairs a Firefight field with a dot-path into the JSON payload. Path segments descend into nested objects, and numeric segments index into arrays, so alerts.0.labels.severity means the severity key inside labels of the first element of the alerts array.

Firefight fieldDefault pathUsed for
titletitleThe alert’s display title and the incident name
descriptiondescriptionThe incident summary
serviceserviceRouting conditions, grouping, and catalog lookups
severity_rawseverityMapped to your incident severities via the source’s severity map
statusstatusFiring or resolved. Values like resolved, ok, recovered, and closed mark the alert resolved, anything else means firing
external_ididIdempotency. The same id is never ingested twice
fingerprintfingerprintIdentity for deduplication. Generated from other fields when absent
teamteamRouting conditions and catalog lookups
environmentenvironmentRouting conditions and catalog lookups
urlurlA link to the alert in your tool, opened from the alert’s title

The same dialog also maps the provider’s severity strings, such as critical or P1, to your workspace’s incident severities. Unmapped values fall back to the workspace default severity.

Some tools deliver several alerts in one POST as an array. Set the Batch path on the source to the dot-path of that array, and Firefight fans the request out so each element becomes its own alert. Field paths are then resolved relative to each element, not the whole body. A batch can carry up to 100 alerts per request.

Datadog, Grafana, Prometheus Alertmanager, Sentry and the other tools listed in How alerts work have a dedicated source that needs no field mapping and resolves alerts when the tool does. Use one of those when your tool is on the list.

Once alerts arrive, they follow the normal pipeline. See Routing rules for what happens next, and Testing your routing to dry-run before going live.