Documentation
Meta
The service itself.
3 endpoints · all GET · no key · samples in curl, Python, JavaScript and Go
GET /healthz
Liveness
package main
import (
"encoding/json"
"net/http"
)
func main() {
res, err := http.Get("https://api.up24.app/healthz")
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
}Deliberately boring, because uptime checks parse it and it must not churn. It does not touch Postgres: the deploy gates a release on this, so a database blip would roll back a good release and leave nothing running to report the outage. /readyz is the one that answers for the database, and it is not part of this API.
Responses
200The service is up.
200 returns HealthResponse
statusstringservicestring"core""web""probe"versionstringuptimeSecondsintegertimestring (date-time)
GET /metrics
Prometheus exposition
package main
import (
"encoding/json"
"net/http"
)
func main() {
res, err := http.Get("https://api.up24.app/metrics")
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
}Four gauge families, in Prometheus text format 0.0.4. Everything here was decided by the incident engine and is being repeated in another shape — a scrape derives nothing that /v1/status does not already say.
up24_component_state{venue,component} — 0 operational, 1 degraded, 2 outage, 3 unknown. Combined across the reporting regions by quorum, which is why it carries no region label: no single vantage point owns that number.
up24_component_state_region{venue,component,region} — the same encoding, for what one box saw before the quorum combined it. This is the series that separates "the venue is down" from "our Singapore probe is".
up24_latency_seconds{venue,endpoint,region,percentile} — the most recent complete minute’s percentile, REST only and never combined across regions. One minute is roughly twelve samples, so smooth it with avg_over_time before alerting on it. Seconds rather than the milliseconds the JSON API speaks, and percentile rather than quantile: Prometheus reserves quantile for summaries, whose _sum and _count counters this endpoint does not have and will not invent. The comparable figure on /v1/status is typicalMs, which is a median of the last 24h of per-minute p50s and not a 24h p50 — percentiles do not compose.
up24_incident_open{venue,component,severity} — 1 while an incident of that severity is open, 0 otherwise. Retracted incidents are absent, here as everywhere.
Nothing is omitted. Every venue × component in the registry exports a series on every scrape, and a component with no evidence exports 3 rather than disappearing — an alert that clears because the evidence vanished is the failure this endpoint exists to avoid. The staleness rule applies as it does to the board: five minutes with the engine silent and every state reads 3.
Latency is the one family that omits: there is no value on a latency gauge that means “not measured”, and 0 would be a claim of zero milliseconds.
Responses
200The exposition.429Over the origin rate limit.
GET /openapi.json
This document
package main
import (
"encoding/json"
"net/http"
)
func main() {
res, err := http.Get("https://api.up24.app/openapi.json")
if err != nil {
panic(err)
}
defer res.Body.Close()
var data map[string]any
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
panic(err)
}
}Generated at request time from the same zod schemas the routes parse their responses with, so it cannot describe a field the API does not return.
Responses
200The OpenAPI 3.1 description of this API.