Skip to main content
The listener GraphQL endpoint returns the same published data as the HTTP API. Use it when a page needs several resources at once, such as the station, now-playing track, and today’s schedule, and you want to choose the fields.

Endpoint

  • Use a credential with listener:read. See Authentication for the Bearer prefix.
  • POST takes a JSON body with query and optional variables, operationName, and extensions. See Query GraphQL.
  • GET takes the same fields as URL parameters. variables and extensions are JSON-encoded strings. See Query GraphQL with GET.
  • OPTIONS answers CORS preflight.
  • Responses are Cache-Control: no-store. GraphQL has no ETag layer; use the HTTP resources when you need conditional reads.
  • Unknown, inactive, or public-offline stations return HTTP 404 before the query runs.
  • Keep the token on your server. Browser clients should call your own origin, which forwards the request.

Make a request

The same read with GET. Let curl URL-encode each parameter:
GET runs queries only. Send the previewEditorial mutation with POST.

Playground

Run queries against the live API with a credential for your own station. The preset examples use the fictional rivi-fm slug, so replace it with your station’s slug. The playground sends the request directly from your browser to the RadioTools API. Nothing is stored, and the token is cleared when you leave the page. Listener queries only read published data.

Queries

The table summarizes each field. The GraphQL schema reference documents every argument, type, enum, error code, and JSON shape. Dates are local YYYY-MM-DD strings. values, document, fields, and the weather and traffic snapshots use a JSON scalar, so you cannot select sub-fields inside them. Media bytes are not inlined; use PublicMedia.url, or a smaller rendition from PublicMedia.variants. content accepts the same sort, direction, and field filters as the HTTP collection. See Requests and response handling. nowPlaying and trackHistory reflect encoder observations, not the planned rundown. artworkUrl is omitted when unknown.

Example queries

Published records for one content type, newest first:
Filter and sort records. Several filters must all match:
A record by its slug, with media for a responsive image:
A slug the record used before still resolves. Compare values.slug with the slug you requested, and redirect to the current URL when they differ. Use contentRecord(id:) when you already have the record ID. Now playing with recent tracks:

Errors

Failures return a standard GraphQL errors array. Branch on errors[0].extensions.code, which uses the same stable codes as the REST API, and read issues for validation details.
Each issue has a path and a message. An issue can also carry a stable code and a suggestion, a value you could send instead. The HTTP status follows the most severe error code, for example 400 for VALIDATION_ERROR, 401 for UNAUTHENTICATED, 404 for NOT_FOUND, and 429 for RATE_LIMITED. A resource that is disabled for the station returns NOT_FOUND, except weather and traffic, which return null. See Errors and versioning.

Editorial preview

The previewEditorial mutation renders a draft revision for a headless site’s preview mode. Send it with POST. It needs the listener Bearer token and an X-Preview-Grant header holding a 15-minute preview grant. The playground does not send that header; use it from your server.
PreviewInput takes stationId, recordId, revision, and audience. Never put the grant in a URL.

Live updates

GraphQL has no subscriptions. For live now-playing, on-air, schedule, and content changes, follow the station’s public realtime feed, which station.resources.realtime describes. The TypeScript SDK subscribes for you. See Public realtime feed.

Introspection

The endpoint accepts standard introspection queries, so GraphQL clients and code generators can read the schema from it. The TypeScript SDK provides typed helpers for the same operations; set transport: "graphql" to use them.