Health omits coverage and pagination fields
Health is the source of truth for adapter status, so its _meta includes only request_id and response_generated_at. It omits _meta.sources, _meta.query_coverage, and _meta.pagination entirely.
Developers
Health
Overview
/v1/health
Health is the strict adapter-status source of truth. Use it to inspect adapter freshness, strict live aggregation eligibility, and infrastructure health without overriding data endpoint consumer-usability fields.
Path and query parameters are documented together so the request surface stays easy to scan.
Use the same endpoint across all three snippets. The tabs switch only the client syntax.
cURL
curl -sS "https://api.mountainswitch.co/v1/health" \
-H "Accept: application/json" TypeScript
const response = await fetch(
"https://api.mountainswitch.co/v1/health",
{
headers: {
Accept: "application/json",
},
},
);
const payload = await response.json(); Python
import requests
response = requests.get(
"https://api.mountainswitch.co/v1/health",
headers={"Accept": "application/json"},
)
payload = response.json()
The example response shows the documented JSON envelope with endpoint data in
data and request metadata in
_meta.
{
"data": {
"overall": "degraded",
"adapters": [
{
"adapter_id": "ca-chain-controls",
"jurisdiction": "US-CA",
"feed_type": "chain-controls",
"status": "healthy",
"live_aggregation_eligible": true,
"last_successful_fetch": "2026-03-19T12:47:00Z",
"last_attempted_fetch": "2026-03-19T12:47:00Z",
"consecutive_failures": 0,
"last_error": null,
"record_count": 45,
"average_latency_ms": 340,
"processor": {
"last_completed_cycle": "2026-03-19T12:47:00.000Z",
"last_job_enqueued_at": "2026-03-19T12:47:00.000Z",
"last_job_started_at": "2026-03-19T12:47:01.000Z",
"last_job_completed_at": "2026-03-19T12:47:02.250Z",
"last_queue_lag_ms": 1000,
"last_job_duration_ms": 1250,
"last_job_outcome": "success",
"last_job_error": null
}
},
{
"adapter_id": "ca-lane-closures",
"jurisdiction": "US-CA",
"feed_type": "lane-closures",
"status": "stale",
"live_aggregation_eligible": false,
"last_successful_fetch": "2026-03-19T12:35:00Z",
"last_attempted_fetch": "2026-03-19T12:47:00Z",
"consecutive_failures": 2,
"last_error": "HTTP 503 from upstream",
"record_count": 120,
"average_latency_ms": 890,
"processor": {
"last_completed_cycle": "2026-03-19T12:35:00.000Z",
"last_job_enqueued_at": "2026-03-19T12:47:00.000Z",
"last_job_started_at": "2026-03-19T12:47:18.000Z",
"last_job_completed_at": "2026-03-19T12:47:19.000Z",
"last_queue_lag_ms": 18000,
"last_job_duration_ms": 1000,
"last_job_outcome": "upstream_http_failure",
"last_job_error": "UPSTREAM_HTTP_503"
}
}
]
},
"_meta": {
"request_id": "req_health_docs",
"response_generated_at": "2026-03-19T19:47:30Z"
}
} This reference stays flat on purpose so the documented fields remain easy to scan.
These rows keep the repo-wide rate-limit and infrastructure behavior visible without inventing endpoint-specific transport semantics.
| Status | Code | When it happens |
|---|---|---|
| 429 | RATE_LIMIT_EXCEEDED | The caller exceeded the shared API rate limit. |
| 503 | SERVICE_UNAVAILABLE | D1 or another critical dependency is unavailable. |
These notes capture the contract edges that matter most for consumers of the endpoint.
Health is the source of truth for adapter status, so its _meta includes only request_id and response_generated_at. It omits _meta.sources, _meta.query_coverage, and _meta.pagination entirely.
Clients must not re-derive strict live aggregation eligibility from status or last_successful_fetch. Data endpoint _meta.sources[].live_eligible is the authoritative consumer-usability field for list, summary, and destination-access responses.
GET /v1/health and GET /v1/health/:adapterId are never written to response KV and must always return Cache-Control: no-store.
Subsection
/v1/health/:adapterId
Use the single-adapter health endpoint when the caller needs one adapter's strict status, strict live aggregation eligibility, and bootstrap or missing-health fallback behavior.
Path and query parameters are documented together so the request surface stays easy to scan.
adapterId
Path Requiredstring
Registered adapter identifier such as ca-chain-controls. Unknown identifiers return 404 ADAPTER_NOT_FOUND.
| Name | Location | Required | Type | Description |
|---|---|---|---|---|
| adapterId | Path | Yes | string | Registered adapter identifier such as ca-chain-controls. Unknown identifiers return 404 ADAPTER_NOT_FOUND. |
Use the same endpoint across all three snippets. The tabs switch only the client syntax.
cURL
curl -sS "https://api.mountainswitch.co/v1/health/ca-chain-controls" \
-H "Accept: application/json" TypeScript
const response = await fetch(
"https://api.mountainswitch.co/v1/health/ca-chain-controls",
{
headers: {
Accept: "application/json",
},
},
);
const payload = await response.json(); Python
import requests
response = requests.get(
"https://api.mountainswitch.co/v1/health/ca-chain-controls",
headers={"Accept": "application/json"},
)
payload = response.json()
The example response shows the documented JSON envelope with endpoint data in
data and request metadata in
_meta.
{
"data": {
"adapter_id": "ca-chain-controls",
"jurisdiction": "US-CA",
"feed_type": "chain-controls",
"status": "healthy",
"live_aggregation_eligible": true,
"last_successful_fetch": "2026-03-19T12:47:00Z",
"last_attempted_fetch": "2026-03-19T12:47:00Z",
"consecutive_failures": 0,
"last_error": null,
"record_count": 45,
"average_latency_ms": 340,
"processor": {
"last_completed_cycle": "2026-03-19T12:47:00.000Z",
"last_job_enqueued_at": "2026-03-19T12:47:00.000Z",
"last_job_started_at": "2026-03-19T12:47:01.000Z",
"last_job_completed_at": "2026-03-19T12:47:02.250Z",
"last_queue_lag_ms": 1000,
"last_job_duration_ms": 1250,
"last_job_outcome": "success",
"last_job_error": null
}
},
"_meta": {
"request_id": "req_health_adapter_docs",
"response_generated_at": "2026-03-19T19:47:30Z"
}
} This reference stays flat on purpose so the documented fields remain easy to scan.
These rows keep the repo-wide rate-limit and infrastructure behavior visible without inventing endpoint-specific transport semantics.
| Status | Code | When it happens |
|---|---|---|
| 404 | ADAPTER_NOT_FOUND | The requested adapterId is not present in the registered adapter registry. |
| 429 | RATE_LIMIT_EXCEEDED | The caller exceeded the shared API rate limit. |
| 503 | SERVICE_UNAVAILABLE | D1 or another critical dependency is unavailable. |
These notes capture the contract edges that matter most for consumers of the endpoint.
If health:{adapterId} is missing, the API distinguishes true bootstrap from post-boot missing health using lastCompletedCycle:{adapterId}. The response is synthesized but not written back to KV.
GET /v1/health/:adapterId returns the same public AdapterHealthApiSchema used inside GET /v1/health data.adapters[].
GET /v1/health/:adapterId is not part of the query_coverage cache matrix and must always return Cache-Control: no-store.