For a tenant's own developer: CI/CD, internal monitoring, an incident bot
Incident API
Incident API capability
Authentication
Generate a key: Dashboard → Settings → API keys. The full key is shown exactly once, in that response; it is never displayed again anywhere in the dashboard afterwards. If you lose it, revoke it and create a new one.
Every request:
Authorization: Bearer ibk_live_<...>A missing/malformed header, an unknown or revoked key, or too many requests on one key (see Rate limiting below) all fail the request before it reaches any endpoint logic.
A key is scoped to the one status page (tenant) it was created under. It can never read or write another tenant's data, the same isolation the dashboard's own session-based access already guarantees.
Base URL
https://inbrief.example/api/v1Try a request
Every endpoint below, against this page's own API, with a key you paste in. Nothing is stored: the key stays in this tab and is sent only to the request you run.
Reading status
There is no authenticated read endpoint. Incident and monitor status is public information by design (that is the point of a status page), so reading it needs no key at all. See the Public status API for both endpoints, their full response shapes and the caching rule.
POST/incidents
Create an incident or scheduled maintenance entry.
curl -X POST https://inbrief.example/api/v1/incidents \
-H "Authorization: Bearer ibk_live_<your key>" \
-H "Content-Type: application/json" \
-d '{
"title": "Elevated error rates",
"summary": "We are investigating reports of elevated error rates on the API.",
"monitorSlugs": [
"api"
],
"startedAt": "2026-08-15T09:00:00Z"
}'const response = await fetch('https://inbrief.example/api/v1/incidents', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INBRIEF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"title": "Elevated error rates",
"summary": "We are investigating reports of elevated error rates on the API.",
"monitorSlugs": [
"api"
],
"startedAt": "2026-08-15T09:00:00Z"
}),
});
if (!response.ok) throw new Error(`InBrief responded ${response.status}`);
const incident = await response.json();| Field | Required | Notes |
|---|---|---|
type | no | "incident" (default) or "maintenance". |
title | yes | In your status page's default language (see Localization below). |
summary | yes | Same. |
monitorSlugs | no | Array of your monitors' slugs (dashboard → Monitors). Unknown slugs are silently ignored. |
startedAt | yes | ISO-8601, e.g. 2026-08-15T09:00:00Z. |
resolvedAt | no | ISO-8601. Only set this on create if the incident is already over. |
Response: 201 with the created incident:
{
"id": "inc_example_02",
"type": "incident",
"title": "Elevated error rates",
"summary": "We are investigating reports of elevated error rates on the API.",
"monitorSlugs": [
"api"
],
"startedAt": "2026-08-15T09:00:00.000Z",
"resolvedAt": null
}PATCH/incidents/{id}
Update or resolve an existing incident. This is a partial update: only fields present in the request body change. Anything omitted (including every other language's already-translated text) is left exactly as it was.
Resolve an ongoing incident:
curl -X PATCH https://inbrief.example/api/v1/incidents/{id} \
-H "Authorization: Bearer ibk_live_<your key>" \
-H "Content-Type: application/json" \
-d '{
"resolvedAt": "2026-08-15T10:30:00Z"
}'const response = await fetch('https://inbrief.example/api/v1/incidents/{id}', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.INBRIEF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"resolvedAt": "2026-08-15T10:30:00Z"
}),
});
if (!response.ok) throw new Error(`InBrief responded ${response.status}`);
const incident = await response.json();Reopen one:
{
"resolvedAt": null
}Same fields as POST /incidents above, all optional here. title/summary
cannot be set to an empty string. Response: 200 with the incident's full current state and the
notify value that was applied:
{
"id": "inc_example_02",
"type": "incident",
"title": "Elevated error rates",
"summary": "We are investigating reports of elevated error rates on the API.",
"monitorSlugs": [
"api"
],
"startedAt": "2026-08-15T09:00:00.000Z",
"resolvedAt": "2026-08-15T10:30:00.000Z",
"notify": true
}Editing without telling anyone
PATCH accepts one extra field, notify. Omit it and the update is announced as usual,
with subscriber email and webhook delivery. Send false and the incident is updated silently, with no subscriber email
and no webhook delivery:
{
"summary": "Fixed a typo in the previous wording.",
"notify": false
}Use it for corrections and backfills. Translation still runs either way, so every other language picks up the
edit whether or not it was announced. Any value other than true or false is a
400.
POST/incidents/{id}/updates
Append an update to an incident. This is the endpoint to call repeatedly as an incident develops: it adds to the timeline rather than replacing anything, so the earlier wording survives and readers can see how it progressed.
curl -X POST https://inbrief.example/api/v1/incidents/{id}/updates \
-H "Authorization: Bearer ibk_live_<your key>" \
-H "Content-Type: application/json" \
-d '{
"status": "identified",
"body": "A configuration change at our payment provider was the cause. We are rolling it back."
}'const response = await fetch('https://inbrief.example/api/v1/incidents/{id}/updates', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INBRIEF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"status": "identified",
"body": "A configuration change at our payment provider was the cause. We are rolling it back."
}),
});
if (!response.ok) throw new Error(`InBrief responded ${response.status}`);
const update = await response.json();| Field | Required | Notes |
|---|---|---|
body | yes | The update text, in your status page's default language. |
status | no | investigating (default), identified,
monitoring or resolved. Anything else is a 400. |
notify | no | Defaults to true. false posts the update
without emailing subscribers or delivering an outbound incident webhook. |
Response: 201:
{
"id": "update_example_02",
"incidentId": "inc_example_02",
"status": "identified",
"body": "A configuration change at our payment provider was the cause. We are rolling it back.",
"notify": true,
"resolvedIncident": false
}Posting
"status": "resolved" also closes the incident if it is still open, and
resolvedIncident says whether that happened; it never moves an end time you already set.
Updates are append-only: there is no endpoint to edit or delete one. The record of what was said at a time is
not something to revise; correcting the current account of events is what PATCH /incidents/:id is
for. Every update is translated into your page's other languages by the same AI pass an incident gets, and
appears on the public page's timeline and in GET /api/public/{slug}/incidents under the incident's
updates array.
Localization
title/summary/body are always read and written in your status page's default language,
since an integration is a system, not a person choosing a language preference. Every other active language
is still filled in automatically when multilingual publishing is enabled, and any translation already on
the incident is preserved by a PATCH that does not
touch title/summary.
Side effects
An incident created or updated through the API triggers exactly what a dashboard edit would: AI
translation, subscriber emails, and outbound webhook deliveries. Nothing
behaves differently because the caller was a script instead of a person, except that you can opt out of the
announcement with notify: false on PATCH or when appending an update.
Errors
Every error response is {"error": "<message>"} with a matching HTTP status:
400 (bad input), 401 (missing/invalid/revoked key), 403 (the key has
the wrong scope or the capability is unavailable), 404 (no such incident, or the id belongs to a different tenant),
429 (rate limited).
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Invalid or revoked API key."
}Rate limiting
Each key is limited independently of any account-wide limit, so one compromised or overused key cannot be
used to hammer the incidents endpoint. A 429 means slow down and retry after a short wait.
This API does not currently accept a client Idempotency-Key
header. Reconcile an uncertain create before retrying it so a timeout does not publish a duplicate.