Documentation
Quickstart
Paging incident history, and reading uptime without dropping its denominator. Both are written out in full because both are places a caller gets a plausible wrong answer rather than an error.
Walking the history
limit stops at 200 and one venue having a bad week exceeds that on its own, so the whole history is a walk. The cursor is before — a timestamp, not an offset, because new incidents are inserted at the front of the ordering and an offset would skip a row every time one opened mid-walk.
import time, httpx
BASE = "https://api.up24.app"
def incidents(venue: str, days: int = 90):
"""Every incident for one venue, walking the cursor rather than raising limit."""
before = before_id = None
with httpx.Client(base_url=BASE, timeout=10) as http:
while True:
params = {"venue": venue, "days": days, "limit": 200}
if before:
params["before"], params["beforeId"] = before, before_id
r = http.get("/v1/incidents", params=params)
# The one status worth handling: the API says when to come back.
if r.status_code == 429:
time.sleep(int(r.headers.get("retry-after", "5")))
continue
r.raise_for_status()
page = r.json()["incidents"]
if not page:
return
yield from page
# A short page is the end. The cursor is the last row's start and
# id, never an offset: new incidents are inserted at the front, and
# incidents opened in one tick share a start.
if len(page) < 200:
return
before, before_id = page[-1]["startedAt"], page[-1]["id"]
for incident in incidents("binance"):
print(incident["slug"], incident["severity"], incident["durationMs"])The one status worth handling is 429: the API says when to come back in retry-after, and that header is the whole of the backoff you need. Nothing else here is retryable in a way you can guess at.
Quoting uptime honestly
Every number here is a measurement with a denominator attached. “99.98% uptime” without the check count or the window is not a claim up24 makes anywhere on this site, and anything named typical is a median of daily percentiles rather than the window's own — percentiles do not compose.
import httpx
BASE = "https://api.up24.app"
r = httpx.get(f"{BASE}/v1/reliability", params={"days": 90}, timeout=10)
if r.status_code == 429:
raise SystemExit(f"rate limited, retry in {r.headers['retry-after']}s")
r.raise_for_status()
for v in r.json()["venues"]:
s = v["summary"]
# measuredDays beside days on purpose: a venue watched for eight days of
# ninety has not been 99.99% for a quarter.
print(
f"{v['name']}: {s['uptimePct']:.2f}% of {s['checks']} checks "
f"over {s['measuredDays']}/{s['days']} days, typical p95 {s['typicalP95Ms']}ms"
)measuredDays is printed beside days on purpose: a venue watched for eight days of ninety has not been 99.99% for a quarter, and a dashboard that drops the first number is publishing a claim the data does not support.