Health API

GET /api/v1/health — live snapshot with status, checked_at, and per-component health.

Get a public snapshot of AnyRouter's health: overall status, checked_at and a components breakdown. No API key needed.

This endpoint is unauthenticated. A default curl User-Agent may get 403 HTML from bot protection on the apex. Use https://api.anyrouter.dev/api/v1/health, or send a User-Agent such as -A "my-status-probe/1.0".

Request

No parameters, no auth header. Poll at ≥ 60 s (see Caching).

GET /api/v1/health HTTP/1.1

If a client gets HTML instead of JSON, use the API host (same Worker as https://anyrouter.dev/api/v1/health):

curl https://api.anyrouter.dev/api/v1/health

Response

Success is always HTTP 200. Read status in the body, not the HTTP code. Each component has its own status:

  • components.api is last-hour generation error rate (can be down during a traffic spike). BYOK requests (generations.is_byok = 1) are excluded. A failed request counts as an error only when its final attempt was a real platform outage (404/410, any 5xx, or failure_class health/capability); key-permission failures (401/403, credential) never count.
  • components.providers lists routing backend ids that served traffic in the last hour (cloudflare), not catalog owners (openai, z-ai) and not -byok/-pool backends. Idle backends are omitted. Generations whose provider_id is not a public backend appear as unattributed, so this list and components.api.data.requests_1h share one window. Quarantine, budget-exhausted and smoke-exclusion override the traffic status, so a skipped backend never reads healthy. Errors count by the same real-outage rule as components.api.
  • components.routing.summary.healthy is how many upstreams are routable; it subtracts quarantined and budget-exhausted backends.
  • components.smoke_tests.last_run is the daily catalog smoke (00
    UTC); data.stale is true only when last_run is older than two days.
  • events lists upstream status-change events, newest first, capped at 50. -byok/-pool upstreams never appear.
{
  "status": "healthy",
  "description": "All systems operational.",
  "version": "1.4.0",
  "checked_at": "2026-08-18T12:00:00.000Z",
  "components": {
    "api": {
      "status": "healthy",
      "description": "Processing requests normally. 12847 requests in the last hour with 2.1% error rate.",
      "note": "Derived from the last 1 hour of traffic.",
      "data": {
        "requests_1h": 12847,
        "error_rate": 0.021,
        "latency_ms": { "avg": 340 },
        "cache_hit_rate": 0.35
      }
    },
    "providers": {
      "status": "healthy",
      "description": "All 1 providers that served traffic are operational.",
      "note": "Each row is a routing backend id (`generations.provider_id`), not a catalog model owner. Status is the last-hour error rate, overlaid with quarantine / budget-exhausted / smoke-exclusion.",
      "data": {
        "providers": [
          {
            "name": "cloudflare",
            "status": "healthy",
            "description": "Operating normally (5421 requests, 1.2% errors).",
            "latency_ms": 120,
            "requests_1h": 5421,
            "error_rate": 0.012
          }
        ]
      }
    },
    "smoke_tests": {
      "status": "healthy",
      "description": "All 80 tested models passed.",
      "note": "The daily smoke-test workflow (00:00 UTC) sends a real one-token request through chat/completions, responses, and messages.",
      "data": {
        "total": 80,
        "passed": 80,
        "failed": 0,
        "skipped": 0,
        "last_run": "2026-08-18T00:00:00.000Z",
        "stale": false,
        "cadence": "0 0 * * *"
      }
    },
    "workflows": {
      "status": "healthy",
      "description": "All 8 scheduled workflows are running on cadence.",
      "note": "Each scheduled workflow that has recorded a run is checked against its last run. Jobs that have never run are omitted.",
      "data": {
        "healthy": 8,
        "stale": 0,
        "failing": 0,
        "never_ran": 0,
        "workflows": [
          {
            "kind": "gateway-log-sync",
            "label": "Gateway log sync",
            "state": "healthy",
            "last_status": "success",
            "last_run_at": "2026-08-18T11:45:00.000Z",
            "age_hours": 0.1,
            "detail": "Last run success 0.1h ago."
          }
        ]
      }
    },
    "routing": {
      "status": "healthy",
      "description": "All 84 routing upstreams are healthy.",
      "note": "Live routing health from the smoke-cooldown store, plus active quarantine and monthly-budget suppression.",
      "data": {
        "summary": {
          "total": 84,
          "healthy": 84,
          "deprioritized": 0,
          "excluded": 0,
          "quarantined": 0,
          "budget_exhausted": 0
        },
        "degraded": [],
        "probes": { "checked_at": "2026-08-18T11:08:00.000Z", "stale": false }
      }
    }
  },
  "events": [
    {
      "at": "2026-08-18T11:10:00.000Z",
      "upstream_id": "cerebras",
      "name": "Cerebras",
      "from": "healthy",
      "to": "degraded",
      "message": "HTTP 503: Service Unavailable"
    }
  ]
}
FieldTypeDescription
status"healthy" | "degraded" | "partial" | "down" | "no_signal"Overall state. Same enum is used on every component. partial means some components are degraded while routing still works. no_signal means there is not enough recent traffic to assess.
descriptionstringHuman-readable summary of the overall state.
versionstringRelease tag of the currently-deployed Worker.
checked_atstringISO 8601 timestamp of this snapshot.
componentsobjectBreakdown for api, providers, smoke_tests, workflows, and routing. smoke_tests, workflows, and routing may be null.
eventsarrayChronological upstream status-change events, newest first (capped at 50).

Every component object has status (same enum), description, note (how the check is derived), and data.

Nested fieldTypeDescription
components.api.data.requests_1hintegerRequests in the last hour.
components.api.data.error_ratenumberFraction of those requests that errored (0–1).
components.api.data.latency_ms.avgnumberAverage latency in milliseconds.
components.api.data.cache_hit_ratenumberFraction of requests that hit the prompt cache (0–1).
components.providers.data.providers[]arrayPer-backend rows (name is a routing backend id such as cloudflare, not a catalog owner). Includes status, description, optional latency_ms / error_rate, and requests_1h. Only backends with last-hour traffic appear. Not a top-level providers array.
components.smoke_tests.dataobjecttotal, passed, failed, skipped, last_run (ISO 8601 or null), stale (true only after 2× the daily cadence), and cadence (0 0 * * *).
components.workflows.dataobjectCounts healthy, stale, failing, never_ran, plus workflows[] (kind, label, state, last_status, last_run_at, age_hours, detail). Jobs that never ran or are intentionally paused are omitted, so never_ran is always 0.
components.routing.data.summaryobjecttotal, healthy, deprioritized, excluded, quarantined, budget_exhausted, over public platform upstreams only (unnamed and -byok/-pool upstreams are never counted). healthy subtracts quarantined / budget-exhausted backends that still look smoke-healthy.
components.routing.data.degraded[]arrayDegraded upstreams with id (routing backend id, e.g. google-agent-platform), name (display label — not unique), logo, and state (deprioritized, excluded, quarantined, or budget_exhausted). A backend degraded in several ways appears once per state.
components.routing.data.probesobjectchecked_at (ISO time of the newest upstream reachability check, or null) and stale. stale is true when no check has run for over 2 hours; routing then reports degraded, because its states may be out of date.
events[]arrayEach entry has at (ISO 8601), upstream_id, its display name, from/to (healthy, degraded, down, or unknown), and an optional message from the probe.

Treat any top-level status other than healthy as not fully operational. Pair provider rows with /api/v1/providers for logos and descriptions.

Responses also include X-RateLimit-Limit, X-RateLimit-Window, and X-RateLimit-Tier (anonymous callers use the IP tier). A 429 honors Retry-After. See Rate Limits.

Examples

curl https://api.anyrouter.dev/api/v1/health

Status codes

HTTPBody statusMeaning
200healthyAll scored components are healthy.
200partial / degraded / no_signal / downOne or more components are unhealthy or lack traffic. Inference may still succeed via fallback.
429—Anonymous IP cap (300 req / 60s). Honor Retry-After.

This endpoint does not use HTTP 503 for a down component — read status and components.*.status.

Caching

Anonymous responses are cacheable. The Worker stamps:

Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600

Browsers reuse the body for 60 s; the edge keeps it 5 minutes and may serve it stale for up to 10 minutes while refreshing. Poll at ≥ 60 s.

AnyRouter routes requests to third-party models. Models and outputs are provided as is, with no warranty; you use them at your own risk. Disclaimer