MountainSwitch

Developers

Health

Overview

GET

/v1/health

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.

Parameters

Path and query parameters are documented together so the request surface stays easy to scan.

This endpoint does not accept path or query parameters.

Example request

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"

Example response

The example response shows the documented JSON envelope with endpoint data in data and request metadata in _meta.

200 OK application/json
{
  "data": {
    "overall": "degraded",
    "road_processor": {
      "last_wave_started_at": "2026-03-19T12:47:00.000Z",
      "last_wave_completed_at": "2026-03-19T12:47:08.000Z",
      "last_skipped_at": null,
      "last_outcome": "success",
      "last_adapter_count": 8,
      "lease_ttl_ms": 240000,
      "lease_expires_at": "2026-03-19T12:51:00.000Z",
      "skip_reason": null
    },
    "adapters": [
      {
        "adapter_id": "ca-d8-chain-controls",
        "jurisdiction": "US-CA",
        "feed_type": "chain-controls",
        "status": "healthy",
        "live_aggregation_eligible": true,
        "last_successful_fetch": "2026-03-19T12:47:00.000Z",
        "last_attempted_fetch": "2026-03-19T12:47:00.000Z",
        "consecutive_failures": 0,
        "last_error": null,
        "record_count": 45,
        "average_latency_ms": 340,
        "processor": {
          "last_published_snapshot_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_job_duration_ms": 1250,
          "last_job_outcome": "success",
          "last_job_error": null
        }
      },
      {
        "adapter_id": "ca-d8-lane-closures",
        "jurisdiction": "US-CA",
        "feed_type": "lane-closures",
        "status": "stale",
        "live_aggregation_eligible": false,
        "last_successful_fetch": "2026-03-19T12:35:00.000Z",
        "last_attempted_fetch": "2026-03-19T12:47:00.000Z",
        "consecutive_failures": 2,
        "last_error": "HTTP 503 from upstream",
        "record_count": 120,
        "average_latency_ms": 890,
        "processor": {
          "last_published_snapshot_at": "2026-03-19T12:35:00.000Z",
          "last_job_started_at": "2026-03-19T12:47:18.000Z",
          "last_job_completed_at": "2026-03-19T12:47:19.000Z",
          "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:30.000Z"
  }
}

Response fields

This reference stays flat on purpose so the documented fields remain easy to scan.

data.overall
"healthy" | "degraded" | "stale" | "down"
Worst status across all adapters in the response.
data.adapters
Array<object>
Registered adapters ordered by adapter_id ascending.
data.road_processor
object | null
Best-effort road cron wave observability snapshot. This is troubleshooting metadata only and is null when unavailable.
data.road_processor.last_outcome
"failed" | "skipped" | "started" | "success"
Latest known road cron wave outcome.
data.road_processor.skip_reason
"wave_lease_acquire_failed" | "wave_lease_held" | null
Reason the latest road cron wave skipped, when it skipped.
data.road_processor.lease_expires_at
string | null
Current or last known road wave lease expiration timestamp.
data.adapters[].adapter_id
string
Registered adapter identifier.
data.adapters[].jurisdiction
string
Canonical jurisdiction code owned by the adapter.
data.adapters[].feed_type
string
Registered feed type for the adapter, such as chain-controls or lane-closures.
data.adapters[].status
"healthy" | "degraded" | "stale" | "down"
Strict request-time adapter status after monotonic worsening.
data.adapters[].live_aggregation_eligible
boolean
Strict processor publish-safety bit. Data endpoints expose their own consumer live_eligible fields.
data.adapters[].last_successful_fetch
string | null
Timestamp of the last successful upstream source check. This is the operator freshness anchor and advances on successful no-op checks.
data.adapters[].last_attempted_fetch
string | null
Timestamp of the last attempted fetch, or null before the first attempt.
data.adapters[].consecutive_failures
number
Current consecutive failure count for the adapter.
data.adapters[].last_error
string | null
Last error string for the adapter when one exists.
data.adapters[].record_count
number
Record count reported by the adapter health snapshot.
data.adapters[].average_latency_ms
number | null
Average fetch latency in milliseconds when available.
data.adapters[].processor
object
Coalesced processor telemetry for operator troubleshooting. Do not use processor fields as upstream freshness anchors.
data.adapters[].processor.last_published_snapshot_at
string | null
Latest material adapter snapshot timestamp that the processor reports as safely published. It may be older than last_successful_fetch when unchanged data is intentionally not republished.
data.adapters[].processor.last_job_completed_at
string | null
Latest persisted processor telemetry completion time. Successful no-op cycles may be coalesced, so this is not an exact per-poll audit timestamp.
data.adapters[].processor.last_job_outcome
string | null
Stable outcome name for the last known processor job, such as success or d1_write_failure.
_meta.request_id
string
Request identifier for debugging and support workflows.
_meta.response_generated_at
string
ISO timestamp describing when the API assembled the response.

Errors

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.

Notes

These notes capture the contract edges that matter most for consumers of the endpoint.

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.

live_aggregation_eligible is authoritative

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.

Use last_successful_fetch for source-check freshness

For operator freshness, use data.adapters[].last_successful_fetch. Processor fields are coalesced troubleshooting telemetry and may lag during repeated successful no-op cycles to avoid unnecessary durable writes.

road_processor is operator metadata

road_processor explains road cron wave retry states such as a still-held wave lease. It must not be used to override adapter status, data endpoint query_coverage, or _meta.sources[].live_eligible.

Health responses are always no-store

GET /v1/health and GET /v1/health/:adapterId are never written to response KV and must always return Cache-Control: no-store.

Subsection

GET

/v1/health/:adapterId

Health by adapter

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.

Parameters

Path and query parameters are documented together so the request surface stays easy to scan.

adapterId

Path Required

string

Registered adapter identifier such as ca-d8-chain-controls. Unknown identifiers return 404 ADAPTER_NOT_FOUND.

Example request

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-d8-chain-controls" \
  -H "Accept: application/json"

Example response

The example response shows the documented JSON envelope with endpoint data in data and request metadata in _meta.

200 OK application/json
{
  "data": {
    "adapter_id": "ca-d8-chain-controls",
    "jurisdiction": "US-CA",
    "feed_type": "chain-controls",
    "status": "healthy",
    "live_aggregation_eligible": true,
    "last_successful_fetch": "2026-03-19T12:47:00.000Z",
    "last_attempted_fetch": "2026-03-19T12:47:00.000Z",
    "consecutive_failures": 0,
    "last_error": null,
    "record_count": 45,
    "average_latency_ms": 340,
    "processor": {
      "last_published_snapshot_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_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:30.000Z"
  }
}

Response fields

This reference stays flat on purpose so the documented fields remain easy to scan.

data.adapter_id
string
Registered adapter identifier for the returned health record.
data.jurisdiction
string
Canonical jurisdiction code owned by the adapter.
data.feed_type
string
Registered feed type for the adapter, such as chain-controls or lane-closures.
data.status
"healthy" | "degraded" | "stale" | "down"
Strict request-time adapter status.
data.live_aggregation_eligible
boolean
Strict processor publish-safety bit for the adapter.
data.last_successful_fetch
string | null
Timestamp of the last successful upstream source check. This is the operator freshness anchor and advances on successful no-op checks.
data.last_attempted_fetch
string | null
Timestamp of the last attempted fetch, or null before the first attempt.
data.consecutive_failures
number
Current consecutive failure count for the adapter.
data.last_error
string | null
Last error string for the adapter when one exists.
data.record_count
number
Record count reported by the adapter health snapshot.
data.average_latency_ms
number | null
Average fetch latency in milliseconds when available.
data.processor
object
Coalesced processor telemetry for operator troubleshooting. Do not use processor fields as upstream freshness anchors.
data.processor.last_published_snapshot_at
string | null
Latest material adapter snapshot timestamp that the processor reports as safely published. It may be older than last_successful_fetch when unchanged data is intentionally not republished.
data.processor.last_job_completed_at
string | null
Latest persisted processor telemetry completion time. Successful no-op cycles may be coalesced, so this is not an exact per-poll audit timestamp.
data.processor.last_job_outcome
string | null
Stable outcome name for the last known processor job, such as success or d1_write_failure.
_meta.request_id
string
Request identifier for debugging and support workflows.
_meta.response_generated_at
string
ISO timestamp describing when the API assembled the response.

Errors

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.

Notes

These notes capture the contract edges that matter most for consumers of the endpoint.

Single-adapter health uses the same fallback rules

If health:{adapterId} is missing or corrupt, the API synthesizes conservative unavailable health for the requested adapter. The response is not written back to KV.

The single-adapter shape matches one list entry

GET /v1/health/:adapterId returns the same public AdapterHealthApiSchema used inside GET /v1/health data.adapters[].

Single-adapter health is also no-store

GET /v1/health/:adapterId is not part of the query_coverage cache matrix and must always return Cache-Control: no-store.