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.

# The cursor is `before` and `beforeId`, the last row's start and id — not
# an offset, because new incidents are inserted at the front, and not the start
# alone, because incidents opened in one tick share one.
BASE="https://api.up24.app"
BEFORE=""
BEFORE_ID=""

while :; do
  URL="$BASE/v1/incidents?venue=binance&days=90&limit=200${BEFORE:+&before=$BEFORE&beforeId=$BEFORE_ID}"

  # -w appends the status and the retry hint after the body, so one call gets
  # all three. %header{} needs curl 7.83 or newer.
  OUT=$(curl -s -w '\n%{http_code}\n%header{retry-after}' "$URL")
  RETRY=$(printf '%s' "$OUT" | tail -n1)
  CODE=$(printf '%s' "$OUT" | tail -n2 | head -n1)
  BODY=$(printf '%s' "$OUT" | sed '$d' | sed '$d')

  # The one status worth handling: the API says when to come back, and that
  # header is the whole of the backoff. Five seconds only if it said nothing.
  if [ "$CODE" = "429" ]; then sleep "${RETRY:-5}"; continue; fi

  printf '%s' "$BODY" | jq -r '.incidents[] | [.slug, .severity, .durationMs] | @tsv'

  COUNT=$(printf '%s' "$BODY" | jq '.incidents | length')
  [ "$COUNT" -lt 200 ] && break
  BEFORE=$(printf '%s' "$BODY" | jq -r '.incidents[-1].startedAt')
  BEFORE_ID=$(printf '%s' "$BODY" | jq -r '.incidents[-1].id')
done

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.

# Uptime with its denominator, which is the only way up24 quotes one.
# measuredDays beside days on purpose: a venue watched for eight days of
# ninety has not been 99.99% for a quarter.
curl -s "https://api.up24.app/v1/reliability?days=90" \
  | jq -r '.venues[]
      | "\(.name): \(.summary.uptimePct)% of \(.summary.checks) checks "
      + "over \(.summary.measuredDays)/\(.summary.days) days, "
      + "typical p95 \(.summary.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.