Model Service Health
Status:
stableCategory:model_servicesAdded:2026-06-24Last reviewed:2026-06-24
Summary
Reports the health of every model the engine offers. A single
authenticated call returns one status per model -- ok, unreachable,
or unconfigured -- so a status page or monitor can show the engine's
model fleet at a glance. The engine checks each model on your behalf;
you pass no model name, body, or list.
Endpoint
| Field | Value |
|---|---|
| Method | GET |
| Path | /api/model_services/health |
| Full URL | https://engine.tripod-health.com/api/model_services/health |
| Authentication | API key (required) |
| Request body | none |
| Response body | application/json |
| Idempotent | Yes |
| Rate-limited | Yes |
Purpose
The engine offers a catalog of models it can run as part of its analytics. Those models are not directly reachable by callers -- only the engine can reach them. This endpoint is the supported way to see whether they are healthy: the engine reads its own model catalog, checks each entry, and returns the collected result.
It is the model-fleet counterpart to the API health check. Use the API health check to answer "is the engine itself up?"; use this endpoint to answer "are the engine's models available?".
Authentication
Send a valid API key in the apikey header. A missing or unknown key
returns 401 Unauthenticated before the request reaches this endpoint.
See authentication.
Request
Headers
| Header | Required | Description |
|---|---|---|
apikey | Yes | Consumer API key. |
X-Request-ID | No | Optional client-generated correlation ID, up to 128 characters. If omitted, one is generated and returned in the X-Request-ID response header. |
Path / query parameters
None. The model list is server-side knowledge; you do not select which models to check.
Body
None. Any body on a GET request is ignored.
Response
Success — 200 OK
Returned whenever the engine can read its model catalog, regardless of
whether individual models are healthy. Per-model problems are reported
inside the list, not as a non-200 status.
{
"services": [
{ "name": "model_a", "status": "ok", "latency_ms": 38 },
{ "name": "model_b", "status": "unreachable", "latency_ms": 4002 },
{ "name": "model_c", "status": "unconfigured", "latency_ms": null }
],
"checked_at": "2026-06-24T17:32:10.812Z"
}
The model names above are illustrative. The list reflects whatever models the engine currently publishes, in catalog order; treat the set as dynamic rather than hard-coding it.
Response fields
| Field | Type | Always present | Description |
|---|---|---|---|
services | array | Yes | One entry per model in the engine's catalog. Empty array if the catalog lists no models. |
services[].name | string | Yes | The model's identifier, stable across calls. |
services[].status | string | Yes | One of "ok", "unreachable", or "unconfigured" (see below). |
services[].latency_ms | integer | null | Yes | Round-trip time of the health check in milliseconds, or null when no response was measured (unconfigured, or a check that never completed). |
checked_at | string (ISO 8601 UTC) | Yes | Server timestamp when the checks were run. |
Status values
| Value | Meaning |
|---|---|
ok | The model responded healthy within the check window. |
unreachable | The model is configured for traffic but did not report healthy -- it timed out or returned an error. Treat as a model-side problem. |
unconfigured | The model is listed in the engine's catalog but is not currently wired for traffic. This is not an error -- the model simply is not available yet. |
Status codes
| Code | Meaning | When |
|---|---|---|
200 | OK | The catalog was read and per-model results returned. Individual models may still be unreachable or unconfigured. |
401 | Unauthenticated | Missing or invalid API key. |
402 | PaymentRequired | Account or key credit balance exhausted. See credits. |
404 | NotFound | Wrong path or method. GET /api/model_services/health is the only supported form. |
429 | RateLimited | Per-consumer rate limit exceeded. See Retry-After. |
503 | ServiceUnavailable | The engine could not read its model catalog. The standard error envelope is returned, not the health body. |
5xx (other) | Varies | Unexpected failure. request_id identifies the call in server logs. |
Error envelope
Non-200 responses (other than the gateway 401) use the standard
error envelope:
{
"timestamp": "2026-06-24T17:32:10.812Z",
"error": "ServiceUnavailable",
"message": "Model catalog is temporarily unavailable",
"request_id": "8f2c3b1d-5e4a-4a9c-9b1e-2a7f1d3e4c5b"
}
See errors for the full code list and envelope extras.
Examples
The language-specific invocations below assume the call() helper (or
its equivalent) from quickstart.md. Copy that
scaffolding once; the per-endpoint calls here reuse it.
1. Canonical request and response
Send:
GET /api/model_services/health HTTP/1.1
Host: engine.tripod-health.com
apikey: $ENGINE_API_KEY
X-Request-ID: docs-model-health-canonical
Receive (200 OK):
{
"services": [
{ "name": "model_a", "status": "ok", "latency_ms": 38 },
{ "name": "model_b", "status": "unreachable", "latency_ms": 4002 },
{ "name": "model_c", "status": "unconfigured", "latency_ms": null }
],
"checked_at": "2026-06-24T17:32:10.812Z"
}
2. Calling the endpoint in your language
curl
curl -sS "https://engine.tripod-health.com/api/model_services/health" \
-H "apikey: $ENGINE_API_KEY"
Python (requests)
# Uses the call() helper from quickstart.md.
fleet = call("GET", "/api/model_services/health")
unhealthy = [s["name"] for s in fleet["services"] if s["status"] == "unreachable"]
if unhealthy:
print("unreachable models:", ", ".join(unhealthy))
else:
print("all configured models healthy")
Node.js (native fetch)
// Uses the call() helper from quickstart.md.
const fleet = await call("GET", "/api/model_services/health");
const unreachable = fleet.services.filter((s) => s.status === "unreachable");
if (unreachable.length > 0) {
console.warn("unreachable models:", unreachable.map((s) => s.name).join(", "));
}
TypeScript
// Uses the typed call<T>() helper from quickstart.md.
interface ModelStatus {
name: string;
status: "ok" | "unreachable" | "unconfigured";
latency_ms: number | null;
}
interface FleetHealth {
services: ModelStatus[];
checked_at: string;
}
const fleet = await call<FleetHealth>("GET", "/api/model_services/health");
const degraded = fleet.services.some((s) => s.status === "unreachable");
if (degraded) {
throw new Error("one or more models are unreachable");
}
PowerShell
# Uses the Invoke-Engine helper from quickstart.md.
$fleet = Invoke-Engine -Method Get -Path "/api/model_services/health"
$down = $fleet.services | Where-Object { $_.status -eq "unreachable" }
if ($down) {
Write-Warning "unreachable models: $(($down | ForEach-Object { $_.name }) -join ', ')"
}
3. Error scenarios
Missing API key
curl -sS "https://engine.tripod-health.com/api/model_services/health"
Receive (401):
{
"message": "No API key found in request",
"request_id": "cd27261422d41501f632143b590d7001"
}
401 bodies carry only message and request_id, not the full error
envelope. Branch on the status code, not the message string. See
authentication.md.
Catalog unavailable
If the engine cannot read its model catalog, it returns the standard error envelope instead of the health body:
{
"timestamp": "2026-06-24T17:32:10.812Z",
"error": "ServiceUnavailable",
"message": "Model catalog is temporarily unavailable",
"request_id": "8f2c3b1d-5e4a-4a9c-9b1e-2a7f1d3e4c5b"
}
Distinguish this from a healthy response with degraded models: a 200
always carries the services array; a 503 carries error. Both
include request_id.
Intended use
- Status pages. Surface per-model status on an operational dashboard. Each entry maps directly to a row.
- Fleet monitoring. Alert when a model that is normally
okflips tounreachable. - Pre-flight checks. Before a batch that relies on a specific
model, confirm that model reports
ok.
Mistaken use
- Do not use this to check whether the engine itself is up. It reports model availability, not API-path health. Use the API health check for that.
- Do not treat
unconfiguredas an outage. It means the model is not wired for traffic yet, not that it failed. Onlyunreachableindicates a problem with a model that is supposed to be serving. - Do not expect a top-level health field. There is no overall
rollup; derive fleet health by inspecting each entry's
status. - Do not select a model with query parameters. The engine always checks its full catalog; there is no per-model variant of this call.
- Do not poll at sub-second frequency. It counts against your rate limit like any other authenticated call. Standard uptime-monitor cadence (30-60 seconds) is the expected pattern.
Debugging
- Capture the
request_id. It is in the error envelope and in theX-Request-IDresponse header. Every support ticket starts here. 401— your API key was rejected. Confirm theapikeyheader is present and the key has not been rotated.402 PaymentRequired— the account or key is out of credits. See credits.429 RateLimited— respect theRetry-Afterheader and slow your cadence.- A model shows
unreachable— the model is configured but not answering. This is a model-side condition; retry after a short backoff. If it persists, quote therequest_idand the modelnamein a ticket. - A model shows
unconfigured— expected for models not yet wired for traffic. No action needed. 503 ServiceUnavailable— the engine could not read its model catalog. Usually transient; retry with backoff and quote therequest_idif it persists.
Rate limits
Treat this endpoint like any other authenticated call when choosing monitor cadence. See rate-limits.md.
Related endpoints
GET /api/health/check— authenticated end-to-end health of the engine itself.GET /api/version/get— build, catalog, and deploy metadata.
Change history
| Date | Change |
|---|---|
| 2026-06-24 | Initial publication. |