REST API

Health

Two open probes for uptime monitors. No key, and not the agent error envelope.

Read as Markdown

Two routes an uptime monitor or a load balancer can call with no API key. They answer in their own small shape, never the { error: { code, ... } } envelope every other route uses.

EndpointChecksBrake
GET /healthNothing. The API process answeredNone
GET /health/readyOne database query, with a 3 second timeout60 requests a minute per IP address
  • Both send Cache-Control: no-store.
  • No key needed. A key sent anyway is ignored.
  • No version, commit or region in either body.

Liveness

GET/api/v1/healthNo auth

Touches nothing but the process. Use it to ask "is the API up".

Terminal
curl -s https://app.riffads.com/api/v1/health
Response: 200
{
  "ok": true,
  "status": "ok",
  "service": "riffads-api"
}

This is the only answer it gives. Anything else (a timeout, a 5XX from the platform in front) means the API is down.

Readiness

GET/api/v1/health/readyNo auth

Runs one query against the database. Use it to ask "can the API serve a real request".

Terminal
curl -s -w "\n%{http_code}\n" https://app.riffads.com/api/v1/health/ready
Response: 200
{
  "ok": true,
  "status": "ready",
  "checks": { "database": "ok" }
}
Response: 503
{
  "ok": false,
  "status": "unavailable",
  "checks": { "database": "down" }
}
  • 503 when the query fails or takes longer than 3 seconds.
  • The reason is never in the body. Only database: "down".

The IP brake

/health/ready does real work, so it is braked at 60 requests a minute per IP address. Over it:

Response: 429
{
  "error": "too_many_requests",
  "error_description": "Too many requests from this address. Please wait and try again."
}
  • Sent with Retry-After in seconds and Cache-Control: no-store.
  • /health is never braked.
  • One monitor every 30 seconds is far below it.

What healthy does not mean

  • Readiness checks the database only. Renders run on outside model providers. A provider outage shows up on the generation (provider_unavailable), not here.
  • A healthy probe does not mean your key works. Test the key with a cheap read such as GET /capabilities. Authentication.

Branch on the HTTP status

Both probes answer ok plus status. Branch on the HTTP status first (200, 429 or 503), then on status. Never parse them as the agent envelope: there is no error.code and no retryable here.

Worked example: a monitor

Poll liveness often and readiness less often:

Terminal
# Every 30 seconds: is the API up?
curl -sf https://app.riffads.com/api/v1/health > /dev/null || echo "RiffAds API down"

# Every 2 minutes: can it serve a request?
code=$(curl -s -o /dev/null -w "%{http_code}" https://app.riffads.com/api/v1/health/ready)
[ "$code" = "200" ] || echo "RiffAds API not ready ($code)"

A 429 from readiness means your monitors share an address and poll too often. Slow them down: it is not an outage.

On this page