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

statusstring
servicestring

"core""web""probe"

versionstring
uptimeSecondsinteger
timestring (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.