API examples
The endpoints a service uses, with real requests and responses. The full endpoint list is in the generated API reference.
Base URL: https://shriek.dev. Bodies are JSON
(Content-Type: application/json); times are Unix seconds. Every /v1/
example sends a ChirpAuth machine token; see
Authentication. $AUTH below stands for:
AUTH=(-H "Authorization: Bearer $SHRIEK_TOKEN" -H "Content-Type: application/json")
A source is always an object with two fields, each 1 to 256 bytes:
{"service": "billing", "component": "nightly-export"}
Post an alert
POST /v1/shriek/alert
curl https://shriek.dev/v1/shriek/alert "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "deploy"},
"severity": "warn",
"title": "deploy rolled back",
"detail": "health check failed on 2 of 3 hosts; rolled back to v41"
}'
| Field | Required | Rules |
|---|---|---|
source | Yes | A source |
severity | Yes | info, warn or critical. critical notifies phones. |
title | Yes | 1 to 256 bytes |
detail | No | Up to 4096 bytes. Defaults to "". |
Response, 200 OK, the recorded alert:
{
"source": {"service": "billing", "component": "deploy"},
"severity": "warn",
"title": "deploy rolled back",
"detail": "health check failed on 2 of 3 hosts; rolled back to v41",
"at": 1793911347
}
Each call appends a new alert, including a retry of the same body.
Register a source
POST /v1/shriek/expectations
curl https://shriek.dev/v1/shriek/expectations "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "nightly-export"},
"period_secs": 3600
}'
| Field | Required | Rules |
|---|---|---|
source | Yes | A source |
period_secs | Yes | At least 60 |
since | No | Unix seconds. The first deadline is since + period_secs. Defaults to now. |
Response, 200 OK. Note the period comes back as period:
{
"source": {"service": "billing", "component": "nightly-export"},
"period": 3600,
"since": 1793911347
}
Send a heartbeat
POST /v1/shriek/heartbeat
curl https://shriek.dev/v1/shriek/heartbeat "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "nightly-export"}
}'
{"ok": true, "at": 1793911347}
404 if the source is not registered.
List sources
GET /v1/shriek/expectations lists every registered source with its last
heartbeat and status:
[
{
"source": {"service": "billing", "component": "nightly-export"},
"period_secs": 3600,
"since": 1793911347,
"last_seen": 1793911347,
"status": {"state": "firing", "since": 1793914953}
}
]
last_seen is null before the first heartbeat. status is
{"state": "ok"}, or {"state": "firing", "since": <when it started>}.
Retire a source
DELETE /v1/shriek/expectations with the source in the body:
curl -X DELETE https://shriek.dev/v1/shriek/expectations "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "nightly-export"}
}'
{
"retired": true,
"source": {"service": "billing", "component": "nightly-export"}
}
404 if the source isn’t registered (never was, or is already retired). See
Dead-man’s switches for what retiring does.
Read the board
GET /v1/shriek/board
[
{
"service": "billing",
"health": "red",
"firing": [{"service": "billing", "component": "nightly-export"}]
}
]
Read the feed
GET /v1/shriek/alerts returns every alert, oldest first. Add
?since=<unix seconds> for alerts recorded at or after that time.
GET /v1/shriek/alerts/{service} returns one service’s alerts.
[
{
"source": {"service": "billing", "component": "deploy"},
"severity": "warn",
"title": "deploy rolled back",
"detail": "health check failed on 2 of 3 hosts; rolled back to v41",
"at": 1793911347
},
{
"source": {"service": "billing", "component": "payments"},
"severity": "critical",
"title": "card payments failing",
"detail": "processor returns 503 for every charge",
"at": 1793911347,
"incident": {"id": "billing/payments#processor-503", "event": "opened"}
},
{
"source": {"service": "billing", "component": "payments"},
"severity": "info",
"title": "resolved",
"detail": "incident `card payments failing` resolved after 1s",
"at": 1793911348,
"incident": {"id": "billing/payments#processor-503", "event": "resolved"}
},
{
"source": {"service": "billing", "component": "nightly-export"},
"severity": "critical",
"title": "no signal",
"detail": "expected every 3600s; no signal from `billing/nightly-export` for 3606s",
"at": 1793914953
}
]
incident is present only on alerts that open or resolve an incident. The
feed is not paged: a call returns everything that matches.
Open an incident
POST /v1/shriek/incidents
curl https://shriek.dev/v1/shriek/incidents "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "payments"},
"severity": "critical",
"title": "card payments failing",
"detail": "processor returns 503 for every charge",
"dedup_key": "processor-503"
}'
| Field | Required | Rules |
|---|---|---|
source, severity, title, detail | As for an alert | |
dedup_key | No | Makes the id {service}/{component}#{dedup_key}, which must fit in 256 bytes. Without it the id is a random UUID. |
Response, 200 OK, the open incident. Sending the same request again while it
is open returns the same body and records nothing:
{
"id": "billing/payments#processor-503",
"source": {"service": "billing", "component": "payments"},
"severity": "critical",
"title": "card payments failing",
"since": 1793911347
}
GET /v1/shriek/incidents lists the open incidents in this shape.
Resolve an incident
POST /v1/shriek/incidents/resolve
curl https://shriek.dev/v1/shriek/incidents/resolve "${AUTH[@]}" -d '{
"id": "billing/payments#processor-503"
}'
{"resolved": true, "id": "billing/payments#processor-503", "down_for_secs": 1}
404 if no incident with that id is open.
Publish a component
POST /v1/shriek/public/components puts a registered source on your public
board under a label of 1 to 256 bytes:
curl https://shriek.dev/v1/shriek/public/components "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "nightly-export"},
"label": "Data exports"
}'
{"source": {"service": "billing", "component": "nightly-export"}, "label": "Data exports"}
404 if the source isn’t a registered expectation (never registered, or
retired). Retiring a source also takes its component off the board.
GET /v1/shriek/public/components lists them in this shape.
DELETE /v1/shriek/public/components takes one off the board. A service
with no components left leaves the board, and its updates leave the page:
curl -X DELETE https://shriek.dev/v1/shriek/public/components "${AUTH[@]}" -d '{
"source": {"service": "billing", "component": "nightly-export"}
}'
{"removed": true, "source": {"service": "billing", "component": "nightly-export"}}
404 if no component is published for that source. Publishing it again puts
it back.
Post a public update
POST /v1/shriek/public/updates; message is 1 to 256 bytes:
curl https://shriek.dev/v1/shriek/public/updates "${AUTH[@]}" -d '{
"service": "billing",
"severity": "critical",
"message": "Card payments are failing. We are working with our processor."
}'
{
"service": "billing",
"severity": "critical",
"message": "Card payments are failing. We are working with our processor.",
"at": 1793911348
}
Anyone can read it, and it can’t be edited or removed.
Read the public status page
No credential. For a tenant named acme:
curl -fsS https://shriek.dev/public/acme/board
curl -fsS https://shriek.dev/public/acme/billing/updates
With the component and update above, and the incident still open, these return:
[
{
"service": "billing",
"health": "red",
"components": [{"label": "Payments", "health": "red"}]
}
]
[
{
"service": "billing",
"severity": "critical",
"message": "Card payments are failing. We are working with our processor.",
"at": 1793911348
}
]
Updates are listed oldest first. The HTML page is at
https://shriek.dev/public/acme.