Evenings.fmEvenings Docs

API Reference

Events API Documentation

Updated

The Events API reads a station's published schedule, with no API key needed. Use it to show upcoming shows on your own website, build your own calendar, or link listeners to an event page.

Every published event has a shareable page at https://evenings.fm/e/:id, returned as url in each response.

Base URL

All endpoints are relative to https://api.evenings.co/v1.

Authentication and limits

Both endpoints are public. They're limited to 50 requests per minute per IP address, and going over returns 429 with a Retry-After header in seconds. See Before you ship for how the limits work.

If you own the station, you can send your session token (Authorization: Bearer <token>) to see your own unpublished events and extra fields; the notes on each endpoint say what changes. An invalid or expired token returns 401. We never quietly treat it as a public request, so a broken token is easy to spot.

Endpoints

List station events

Returns a station's published events that start within a date range, in start order.

  • URL: /stations/:slug/events
  • Method: GET
  • Auth required: No
  • URL parameters:
    • slug: the station's slug, the last part of its address (sample-radio for evenings.fm/sample-radio)
  • Query parameters:
    • startDate (optional): ISO 8601 date or timestamp, such as 2026-07-01 or 2026-07-01T18:00:00Z. Defaults to the start of the current month.
    • endDate (optional): ISO 8601 date or timestamp. Defaults to the end of the current month. A date on its own includes that whole day, up to 23:59:59.999 UTC.
    • When you send both, endDate must be on or after startDate, and the two can be at most 45 days apart.

Dates without a time are read as UTC.

Example:

curl "https://api.evenings.co/v1/stations/garage/events?startDate=2026-07-01&endDate=2026-07-31"

Response:

[
  {
    "id": "abc123def4",
    "title": "Tuesday Sessions",
    "host": "DJ Name",
    "description": "Weekly vibes",
    "image": "https://cdn.evenings.co/img/abc.jpg",
    "startAt": "2026-07-07T20:00:00.000Z",
    "endAt": "2026-07-07T22:00:00.000Z",
    "timezone": "America/New_York",
    "recurrence": "weekly",
    "status": "scheduled",
    "url": "https://evenings.fm/e/abc123def4"
  }
]
FieldWhat it is
idThe event's public ID, also the last part of url
title, host, description, imageThe event's details. Any of them can be empty or null.
startAt, endAtStart and end as UTC timestamps
timezoneThe IANA time zone the station scheduled the event in, such as America/New_York. Use it to show times the way the station sees them.
recurrencenone, daily, weekly, monthly or monthly_last (the last given weekday of each month)
statusscheduled, running or completed
urlThe event's public page on Evenings

A repeating event appears once for each time it occurs in the range. Each occurrence has its own startAt and endAt but shares the same id and url, so key your list on id and startAt together.

Station owners: the same request with your session token returns every event in the range, including unpublished ones, with the full event object. If one of today's events is broadcasting, it also carries live online and listeners fields. A token for a different station is treated as a public request.

Get event

Returns one published event, with its station and RSVP count.

  • URL: /events/:id
  • Method: GET
  • Auth required: No
  • URL parameters:
    • id: the event's id from List station events (also the last part of its url)

Example:

curl https://api.evenings.co/v1/events/abc123def4

Response:

{
  "id": "abc123def4",
  "title": "Tuesday Sessions",
  "host": "DJ Name",
  "description": "Weekly vibes",
  "image": "https://cdn.evenings.co/img/abc.jpg",
  "startAt": "2026-07-07T20:00:00.000Z",
  "endAt": "2026-07-07T22:00:00.000Z",
  "timezone": "America/New_York",
  "recurrence": "weekly",
  "status": "scheduled",
  "url": "https://evenings.fm/e/abc123def4",
  "station": {
    "name": "Sample Radio",
    "slug": "sample-radio",
    "image": "https://cdn.evenings.co/img/station.jpg"
  },
  "attendeeCount": 12
}

The fields match List station events, plus station (its name, slug and image) and attendeeCount, the number of people who have RSVPed and verified their phone number. For a repeating event, startAt and endAt are those of the first occurrence.

Unpublished and unknown events both return 404, so an unpublished event's existence is never revealed.

Station owners: with your session token, this returns the full event object for your own events, including unpublished ones, and live online and listeners fields while the event is broadcasting.

GET /v1/events/public/:id is deprecated in favor of this endpoint. It still works and sends a Deprecation: true header, but new integrations should use GET /v1/events/:id.

Show upcoming events on your website

A small example that lists a station's events for the current month as links. It calls a public endpoint, so it's safe to run in the browser:

<ul id="events"></ul>
 
<script>
  const slug = "garage"; // your station's slug
 
  fetch(`https://api.evenings.co/v1/stations/${slug}/events`)
    .then((res) => res.json())
    .then((events) => {
      const list = document.getElementById("events");
      for (const event of events) {
        const item = document.createElement("li");
        const link = document.createElement("a");
        link.href = event.url;
        const date = new Date(event.startAt).toLocaleString(undefined, {
          dateStyle: "medium",
          timeStyle: "short",
          timeZoneName: "short",
        });
        link.textContent = `${event.title}, ${date}`;
        item.appendChild(link);
        list.appendChild(item);
      }
    });
</script>

Each time shows in the visitor's own time zone, with the zone named so nobody has to guess. To show the station's time zone instead, pass timeZone: event.timezone to toLocaleString. To show a different window, add startDate and endDate (up to 45 days at a time).

Error responses

Every error body is JSON with title and error, as described in Read errors. Since October 2026, the date errors below are JSON rather than plain text, and the 401 and 429 messages are in error rather than message.

StatusWhenBody
400 Bad RequestDate range longer than 45 days{ "title": "A little cloudy 🌞", "error": "We couldn't accept the request query. startDate and endDate can be at most 45 days apart." }
400 Bad RequestendDate before startDate{ "title": "A little cloudy 🌞", "error": "We couldn't accept the request query. endDate must be on or after startDate." }
400 Bad RequestA date that isn't ISO 8601{ "title": "A little cloudy 🌞", "error": "We couldn't accept the request query. \"startDate\" must be in ISO 8601 date format." }
401 UnauthorizedAn invalid or expired session token was sent{ "title": "The gate is closed 🌞", "error": "The API key or session token is missing or invalid. Send a current one as a Bearer token in the Authorization header." }
404 Not FoundUnknown station slug{ "title": "No resource on the horizon 🌞", "error": "We couldn't find a station with that slug." }
404 Not FoundUnknown or unpublished event{ "title": "No resource on the horizon 🌞", "error": "We couldn't find that event. Check the event ID." }
429 Too Many RequestsMore than 50 requests in a minute from one IP{ "title": "Let the tide settle 🌞", "error": "We've received too many requests from your IP address. Try again after the number of seconds in the Retry-After header." }, with a Retry-After header in seconds
500 Internal Server ErrorSomething failed on our end{ "title": "Sun has set on the server 🌞", "error": "We couldn't finish this request on our end. Try again in a minute." }

Next steps

To show what's on air right now next to what's coming up, pair this with the Streams API. For the station side of events, see How to run an event. If your schedule looks different through the API than it does on Evenings, email contact@evenings.email with the slug and the dates you asked for, and we'll compare them with you.