Open Radio Player Developer API

Public JSON API docs for station health, stream telemetry, system status, and station catalog feeds for apps, dashboards, games, and AI agents.

Live API Status | OpenAPI Schema | LLM Guide | Power Docs API Section

Who This Helps

  • Apps that need a smaller set of recent, reliable radio streams without running their own monitor.
  • Games and companion experiences that want compatibility flags and low-latency stream selection.
  • AI agents that need explicit filters, freshness timestamps, and a stable station catalog.
  • Dashboards, scripts, and automations that need pipeline health plus stream-level telemetry.

Quick Start

  1. Use `/api/v1/stations/programming?ids=...&days=2` for one bounded genre-guide projection with schedule, Now/Next, and live-metadata availability.
  2. Start with `/api/v1/stations/healthy` when you want reliable defaults and smaller payloads.
  3. Use `/api/v1/stations/telemetry` when you want the full stream-variant feed, including at-risk rows.
  4. Check `/api/v1/system/status` before demos, cron jobs, or agent tasks that depend on fresh data.
  5. Join `/api/v1/stations/index.json` with live telemetry by `streamId` or `defaultStreamId` when you need both catalog metadata and health.

Integration Notes

  • Authentication: None. The current public API is read-only and does not require an API key.
  • CORS: JSON endpoints send `Access-Control-Allow-Origin: *` and allow `GET, OPTIONS`.
  • Formats: API responses are UTF-8 JSON. The `/api` landing page is HTML and intended for humans.
  • Freshness: Programming clients must check `sourceObservedAt`, `validFrom`, `validThrough`, `staleAt`, `availability`, and `reason`; CDN freshness never extends source validity.
  • Cache behavior: Schedules cache for five minutes, Now/Next and batch for 30 seconds, approved live metadata for 15 seconds, and operational feeds for one hour. Responses include ETag and Last-Modified.
  • Selection semantics: The healthy endpoint applies database-side health gates first, then compatibility filters, then trims to `limit`.

Key Resources

  • Developer Docs: Search-friendly reference page for apps, games, AI agents, and integrations.
  • Live API Status: Human-readable API landing page with live health checks and endpoint links.
  • OpenAPI Schema: Machine-readable contract for the public JSON endpoints.
  • LLM Guide: Compact endpoint and integration guide for agents and retrieval systems.

Programming guide projection

Path: /api/v1/stations/programming

Canonical provider projection containing factual schedule occurrences, schedule-derived Now/Next, live-metadata availability, provenance, and validity.

Method: GET | Auth: None | Cache: public, s-maxage=30, stale-while-revalidate=60

Ordering: Requested ID order, or canonical catalog order for a genre query.

Highlights

  • Every item identifies `open-radio.programming.v1` and carries source observation, validity, staleness, availability, a machine reason, and source provenance.
  • Unknown IDs return 404; known unsupported, unavailable, and stale stations remain HTTP 200 with empty factual data.
  • Use `/api/v1/stations/{stationId}/schedule`, `/now-next`, or `/now-playing` for individual resources. Schedule requests allow at most 14 days.

Parameters

  • ids (string, default none): Comma-separated canonical station IDs or published aliases; maximum 50. Required when `genre` is absent.
  • genre (string, default none): Exact canonical `genres[]` value. Required when `ids` is absent.
  • from (date, default today): First projected calendar date in `YYYY-MM-DD` form.
  • days (integer, default 2): Projected days, bounded to `1..7`.

Example Request

curl 'https://openradioplayer.com/api/v1/stations/programming?ids=kdfc,kusc,kdb&from=2026-07-19&days=2'

Response Excerpt

{
  "schemaVersion": "open-radio.programming.v1",
  "apiVersion": "v1",
  "generatedAt": "2026-07-19T12:00:00.000Z",
  "availability": "available",
  "reason": "partial_or_complete_results_available",
  "count": 3,
  "items": [
    {
      "stationId": "kdfc",
      "timeZone": "America/Los_Angeles",
      "sourceObservedAt": "2026-07-19T08:21:00.000Z",
      "validThrough": "2026-08-02T07:00:00.000Z",
      "staleAt": "2026-08-02T07:00:00.000Z",
      "availability": "available",
      "reason": "ok",
      "schedule": { "occurrences": [] },
      "nowNext": { "current": null, "next": null },
      "nowPlaying": {
        "availability": "unsupported",
        "reason": "approved_live_track_source_not_available",
        "track": null
      }
    }
  ]
}

Healthy stations

Path: /api/v1/stations/healthy

Recommended starting endpoint for apps, games, AI agents, widgets, and external clients that want recent playable streams.

Method: GET | Auth: None | Cache: public, s-maxage=3600, stale-while-revalidate=21600

Ordering: Sorted by score desc, availabilityPercent desc, averageStartupLatencyMs asc, then streamId asc.

Highlights

  • Echoes the effective filters in `filters` so downstream clients can log exactly what was applied.
  • Each item includes `stationId`, `defaultStreamId`, `streamId`, scalar `genre`, richer `genres[]` / `countries[]` / `languages[]` / `programmingTags[]`, compatibility fields, recent health metrics, and optional `loudnessProfile` data.
  • `count` reflects the final filtered set after compatibility checks and `limit` are applied.

Parameters

  • status (string, default healthy): Health band to query. Defaults to `healthy`.
  • genre (string, default none): Optional scalar/back-compatible genre filter such as `jazz`, `indie`, `classical`, or a canonical value from `genres[]`.
  • country (string, default none): Optional facet filter matched against `countries[]`.
  • language (string, default none): Optional facet filter matched against `languages[]`.
  • programmingTag (string, default none): Optional facet filter matched against `programmingTags[]`; `tag` is accepted as an alias.
  • stationId (string, default none): Optional parent-station filter when you want all variants for one station.
  • limit (integer, default 50): Maximum rows returned. Clamped to `1..200`.
  • minScore (integer, default 86): Minimum health score required for a row to survive the first filter pass.
  • maxStartupLatencyMs (integer, default 1500): Maximum acceptable average startup latency.
  • minAvailabilityPercent (integer, default 80): Minimum rolling availability percentage.
  • maxConsecutiveFailures (integer, default 0): Maximum allowed consecutive probe failures.
  • maxAgeMinutes (integer, default 720): Rejects telemetry older than this threshold.
  • streamType (string, default none): Compatibility filter such as `hls`, `mp3`, `aac`, or `direct`.
  • streamTransport (string, default none): Transport filter: `direct` or `hls`.
  • audioFormat (string, default none): Optional codec/container hint such as `mp3`, `aac`, `ogg`, `opus`, or `flac`.
  • supportsNativeAudio (boolean, default none): Filter for clients that require direct/native browser audio playback.
  • supportsHlsPlayback (boolean, default none): Filter for clients that specifically want HLS-capable rows.

Example Request

curl 'https://openradioplayer.com/api/v1/stations/healthy?genre=jazz&limit=12&minScore=90&maxStartupLatencyMs=1200&maxAgeMinutes=720&supportsNativeAudio=true'

Response Excerpt

{
  "ok": true,
  "generatedAt": "2026-03-21T19:11:52.654Z",
  "telemetryGeneratedAt": "2026-03-21T19:02:19.000Z",
  "filters": {
    "status": "healthy",
    "genre": "jazz",
    "limit": 12,
    "minScore": 90,
    "maxStartupLatencyMs": 1200,
    "maxAgeMinutes": 720,
    "supportsNativeAudio": true
  },
  "count": 12,
  "items": [
    {
      "streamId": "kcsm--hd2-aac",
      "stationId": "kcsm",
      "defaultStreamId": "kcsm",
      "streamLabel": "HD2 AAC+",
      "streamType": "aac",
      "streamTransport": "direct",
      "supportsNativeAudio": true,
      "supportsHlsPlayback": false,
      "status": "healthy",
      "score": 100,
      "availabilityPercent": 100,
      "averageStartupLatencyMs": 1186
    }
  ]
}

Telemetry feed

Path: /api/v1/stations/telemetry

Full stream-variant telemetry feed used by the site itself, including healthy and at-risk rows plus detailed timing and failure counters.

Method: GET | Auth: None | Cache: public, s-maxage=3600, stale-while-revalidate=21600

Ordering: Sorted by genre asc, stationName asc, then streamId asc.

Highlights

  • Returns startup attempts, successes, failures, reconnect counts, buffering events, and recent failure timestamps.
  • Useful for ranking, debugging, dashboards, or agent workflows that need the full health window instead of just healthy rows.
  • If you only need a filtered shortlist, prefer `/api/v1/stations/healthy` to reduce payload size and client-side work.

Parameters

  • stationId (string, default none): Optional parent-station filter that returns all known variants for a station.

Example Request

curl 'https://openradioplayer.com/api/v1/stations/telemetry?stationId=krtu'

Response Excerpt

{
  "ok": true,
  "generatedAt": "2026-03-21T19:11:52.757Z",
  "telemetryGeneratedAt": "2026-03-21T19:02:19.000Z",
  "filters": {
    "stationId": "krtu"
  },
  "count": 2,
  "items": [
    {
      "streamId": "krtu--mp3",
      "stationId": "krtu",
      "streamLabel": "MP3 128",
      "status": "healthy",
      "score": 96,
      "startupAttempts": 183,
      "averageStartupLatencyMs": 161,
      "playbackFailures": 0,
      "reconnects": 0,
      "lastFailureReason": null
    }
  ]
}

System status

Path: /api/v1/system/status

Machine-readable heartbeat for the full monitor -> database -> production API pipeline.

Method: GET | Auth: None | Cache: public, s-maxage=3600, stale-while-revalidate=21600

Ordering: Not ordered. Single object response.

Highlights

  • Includes freshness thresholds, summary metrics, named checks, and the canonical endpoint URLs.
  • Returns HTTP 200 when healthy, HTTP 503 when the system is degraded but still able to report status, and HTTP 500 on unexpected failures.
  • Useful as a lightweight readiness gate before agent jobs or external fetches.

No query parameters.

Example Request

curl 'https://openradioplayer.com/api/v1/system/status' | jq

Response Excerpt

{
  "ok": true,
  "status": "ok",
  "generatedAt": "2026-03-21T19:11:53.374Z",
  "thresholds": {
    "freshTelemetryMinutes": 420,
    "staleTelemetryMinutes": 720
  },
  "summary": {
    "telemetryGeneratedAt": "2026-03-21T19:02:19.000Z",
    "telemetryAgeMinutes": 9.6,
    "healthyStations": 63,
    "averageScore": 95
  },
  "checks": {
    "database": {
      "ok": true,
      "level": "ok",
      "detail": "Connected and queried successfully."
    }
  },
  "endpoints": {
    "landingPage": "https://openradioplayer.com/api",
    "healthyStations": "https://openradioplayer.com/api/v1/stations/healthy"
  }
}

Station catalog

Path: /api/v1/stations/index.json

Static station catalog published by the production site build, including per-station stream variants, city-level coordinates, and compatibility hints.

Method: GET | Auth: None | Cache: public, max-age=0, must-revalidate

Ordering: Build output order from the generated station catalog.

Highlights

  • Includes `version`, `generatedAt`, `count`, `streamVariantCount`, and `items[]`.
  • Each station row exposes scalar `genre` for compatibility plus `genres[]`, `countries[]`, `languages[]`, `programmingTags[]`, `city`, city-level `coordinates`, `defaultStreamId`, `streamCount`, `stream`, and `streams[]`.
  • Join catalog rows with telemetry by `streamId` to combine stable metadata with live health observations.

No query parameters.

Example Request

curl 'https://openradioplayer.com/api/v1/stations/index.json' | jq '.items[0] | {id, genre, genres, countries, languages, defaultStreamId, streamCount}'

Response Excerpt

{
  "version": 1,
  "generatedAt": "2026-03-20T17:29:20.836Z",
  "count": 99,
  "streamVariantCount": 101,
  "items": [
    {
      "id": "cfmz",
      "stationId": "cfmz",
      "stationName": "CFMZ 96.3 - Toronto, ON",
      "genre": "classical",
      "genres": ["classical"],
      "countries": ["Canada"],
      "languages": ["en"],
      "programmingTags": ["classical"],
      "city": "Toronto, ON",
      "coordinates": {
        "latitude": 43.6532,
        "longitude": -79.3832,
        "precision": "city",
        "label": "Toronto, ON"
      },
      "defaultStreamId": "cfmz",
      "streamCount": 1,
      "streams": [
        {
          "id": "cfmz",
          "label": "Primary",
          "transport": "direct",
          "supportsNativeAudio": true,
          "supportsHlsPlayback": false
        }
      ]
    }
  ]
}

Error Model

  • 200: Successful response.
  • 400: Programming date, day count, or batch size is outside the documented bound.
  • 404: Unknown canonical station ID or alias. Known unsupported stations remain HTTP 200 with explicit availability.
  • 405: Method not allowed. Use `GET` for reads and `OPTIONS` for CORS preflight.
  • 500: Unexpected server or data source failure.
  • 503: The system status endpoint can return degraded-but-readable data with HTTP 503 when the pipeline is unhealthy.