Skip to content

How do I Use the Channel API? ​

The Channel API gives your website or app your channel's broadcast information as JSON: what's playing now, your schedule, Catchup, programs and episodes. The API Reference tab on Integration shows every endpoint with your own channel's address filled in.

Before You Start ​

Base URLhttps://stream.cecula.com/api
AuthenticationNone. The endpoints are public and read-only. Anyone with your channel's ID can read them, so treat the data as published
MethodGET
BrowsersCross-origin requests are allowed, so you can call the API straight from a web page
FormatJSON. Times are ISO 8601
Channel IDUse your channel's UUID. The program endpoints also accept its slug. See Your Channel and Program IDs

If a channel or program doesn't exist, you get HTTP 404 and a message:

json
{ "error": "Channel not found" }

Endpoints at a Glance ​

EndpointReturns
GET /channels/{uuid}/statusWhat's playing now. See Now Playing
GET /channels/{uuid}/scheduleRecent and upcoming scheduled broadcasts. See Scheduled Broadcasts
GET /channels/{uuid}/catchupsCatchup entries, with playback links. See Catchup
GET /channels/{channel}/programsThe channel's programs. See Programs
GET /channels/{channel}/programs/currentThe program episode on air now. See Program On Air Now
GET /channels/{channel}/programs/nextThe next airing. See Next and Upcoming Airings
GET /channels/{channel}/programs/upcomingUpcoming airings. See Next and Upcoming Airings
GET /programs/{program}/episodesA program's episodes. See Program Episodes

Now Playing ​

GET /channels/{uuid}/status

Returns what the channel is showing at this moment.

json
{
  "channel_name": "Luma TV",
  "is_live": false,
  "current_video": {
    "id": 412,
    "name": "Morning Devotion — Week 34",
    "description": "Recorded midweek service.",
    "location": "Uyo, Akwa Ibom",
    "thumbnail": "https://stream.cecula.com/storage/thumbnails/412.jpg",
    "start_time": "2026-09-15T09:00:00+01:00",
    "end_time": "2026-09-15T10:30:00+01:00",
    "remaining_time": 1820,
    "remaining_time_human": "30:20"
  },
  "estimated_end_at": "2026-09-15T10:30:00+01:00"
}
FieldMeaning
channel_nameThe channel's name
is_livetrue while a live feed is on air
current_videoWhat's playing, or null if nothing is
current_video.idThe video's ID. Only for scheduled broadcasts
current_video.name, description, locationDetails of what's playing
current_video.thumbnailAn image for it, or null
current_video.start_time, end_timeWhen it started and ends. null for a live broadcast
current_video.remaining_timeSeconds left
current_video.remaining_time_humanTime left as MM:SS or HH:MM:SS, or Live
estimated_end_atWhen this answer is expected to change

current_video describes the first of these that applies:

  1. A program episode in its slot: the episode's name and synopsis (or the program's), its banner, and the slot's times.
  2. A scheduled broadcast: the video's details and the broadcast's times.
  3. A live broadcast: your live event title, description, location and show banner. The times are null, and remaining_time_human is Live.
  4. A playlist:
    • during a time belt, the playlist's name and description, with the belt's times
    • otherwise, the video playing and its times
    • while a logo sting plays, the channel's name and Loading video...

Because program episodes and scheduled broadcasts are checked first, current_video keeps describing them while a live feed interrupts them. Use is_live to tell whether a live feed is on air.

💡 Poll when it changes, not every second

The response can be cached until estimated_end_at, and says so in its Cache-Control header. For live broadcasts, and when the end can't be known, that's 60 seconds. Ask again at estimated_end_at.

Scheduled Broadcasts ​

GET /channels/{uuid}/schedule

Returns broadcasts from the Schedule page that ended in the last two hours or are still to come, in start-time order. Program episodes aren't included. For those, see Next and Upcoming Airings.

json
{
  "channel_name": "Luma TV",
  "schedule_count": 1,
  "schedule": [
    {
      "id": 412,
      "start_time": "2026-09-15T08:00:00.000000Z",
      "end_time": "2026-09-15T09:30:00.000000Z",
      "status": "pending",
      "video": {
        "name": "Morning Devotion — Week 34",
        "description": "Recorded midweek service.",
        "thumbnail": "https://stream.cecula.com/storage/thumbnails/412.jpg"
      }
    }
  ]
}
FieldMeaning
schedule_countHow many broadcasts are returned
schedule[].idThe broadcast's ID
schedule[].start_time, end_timeThe broadcast's times, in UTC (ending in Z)
schedule[].statuspending, live, completed or cancelled
schedule[].videoThe video's name, description and thumbnail

Catchup ​

GET /channels/{uuid}/catchups?page=1

Returns Catchup entries, newest air time first, 15 per page. Add ?page=2 and so on for more.

json
{
  "channel_name": "Luma TV",
  "catchup_count": 37,
  "current_page": 1,
  "last_page": 3,
  "per_page": 15,
  "catchups": [
    {
      "id": 88,
      "title": "Sunday Service — Episode 12: The Word",
      "description": "Opening night of the new season.",
      "start_time": "2026-09-13T08:00:00.000000Z",
      "end_time": "2026-09-13T10:42:10.000000Z",
      "duration": 9730,
      "video": {
        "id": 901,
        "name": "Recording: 2026-09-13 09:00",
        "thumbnail": "https://stream.cecula.com/storage/episodes/ep12.jpg",
        "hls_url": "https://stream.cecula.com/storage/channels/4/media/901/index.m3u8",
        "resolution": "1920x1080"
      }
    }
  ]
}
FieldMeaning
catchup_countThe total number of entries
current_page, last_page, per_pagePaging details
catchups[].title, descriptionThe entry's title and description
catchups[].start_time, end_timeWhen it aired, in UTC
catchups[].durationLength in seconds
catchups[].video.hls_urlThe link to play it in an HLS player
catchups[].video.thumbnail, resolutionIts image and resolution

Programs ​

GET /channels/{channel}/programs

Returns the channel's active and paused programs, in name order. Draft and archived programs are never included.

ParameterMeaning
statusactive or paused
typelive or on_demand
per_pagePrograms per page. Defaults to 15, up to 50
json
{
  "channel_name": "Luma TV",
  "programs": [
    {
      "id": 3,
      "name": "Sunday Service",
      "slug": "sunday-service",
      "synopsis": "Weekly worship, live from Uyo.",
      "banner_url": "https://stream.cecula.com/storage/programs/service.jpg",
      "trailer_url": null,
      "type": "live",
      "status": "active",
      "available_on_demand": true,
      "episodes_count": 12,
      "schedule": [
        { "id": 9, "day_of_week": 0, "day": "Sunday", "start_time": "09:00", "duration_minutes": 180 }
      ]
    }
  ],
  "meta": { "total": 1, "current_page": 1, "last_page": 1, "per_page": 15 }
}

See The Program Object.

Program On Air Now ​

GET /channels/{channel}/programs/current

Returns the program episode whose slot is open now. It's safe to call on any channel, including one with no programs.

json
{
  "channel_name": "Luma TV",
  "program": { "id": 3, "name": "Sunday Service", "type": "live", "status": "active" },
  "episode": { "id": 44, "episode_number": 12, "name": "The Word", "type": "live", "status": "on_air" },
  "status": "on_air",
  "started_at": "2026-09-13T09:00:00+01:00",
  "ends_at": "2026-09-13T12:00:00+01:00",
  "playback_source": "livestream",
  "banner_url": "https://stream.cecula.com/storage/episodes/ep12.jpg"
}

The program and episode objects above are shortened. See The Program Object and The Episode Object.

playback_sourceWhat viewers are getting
livestreamThe live feed
pre_recordedThe pre-recorded episode
trailerThe trailer, while a live episode waits for its feed
standbyThe starts soon card, while a live episode waits for its feed
fallbackThe channel's usual content, because nothing else is available

When no slot is open, status is off_air and the other fields are null:

json
{
  "channel_name": "Luma TV",
  "program": null,
  "episode": null,
  "status": "off_air",
  "started_at": null,
  "ends_at": null,
  "playback_source": null
}

Next and Upcoming Airings ​

GET /channels/{channel}/programs/next

Returns the soonest airing still to come, under next, or null if nothing is booked.

json
{
  "channel_name": "Luma TV",
  "next": {
    "id": 118,
    "program": { "id": 3, "name": "Sunday Service" },
    "episode": { "id": 45, "episode_number": 13, "name": "Foundations" },
    "starts_at": "2026-09-20T09:00:00+01:00",
    "ends_at": "2026-09-20T12:00:00+01:00",
    "start_time": "09:00",
    "duration_minutes": 180,
    "episode_type": "live",
    "state": "upcoming",
    "went_live_at": null,
    "banner_url": "https://stream.cecula.com/storage/programs/service.jpg"
  }
}
GET /channels/{channel}/programs/upcoming

Returns upcoming airings, soonest first, under upcoming, with a count. An episode on air now is included at the top.

ParameterMeaning
limitHow many airings. Defaults to 10, up to 50
fromOnly airings at or after this time. Defaults to now
toOnly airings starting at or before this time

For example, /programs/upcoming?limit=3 returns the next three. /programs/next/3 does the same.

See The Airing Object.

Program Episodes ​

GET /programs/{program}/episodes

Returns a program's episodes, highest episode number first. It works for active and paused programs.

ParameterMeaning
statusdraft, scheduled, on_air, completed, missed or cancelled
fromOnly episodes with an airing at or after this time
toOnly episodes with an airing at or before this time
per_pageEpisodes per page. Defaults to 15, up to 50
json
{
  "program": { "id": 3, "name": "Sunday Service" },
  "episodes": [
    {
      "id": 44,
      "episode_number": 12,
      "name": "The Word",
      "synopsis": "Opening night of the new season.",
      "banner_url": "https://stream.cecula.com/storage/episodes/ep12.jpg",
      "trailer_url": null,
      "type": "live",
      "status": "completed",
      "available_on_demand": true,
      "on_demand": {
        "id": 901,
        "duration": 9730,
        "hls_url": "https://stream.cecula.com/storage/channels/4/media/901/index.m3u8",
        "thumbnail_url": "https://stream.cecula.com/storage/episodes/ep12.jpg"
      },
      "broadcasts": []
    }
  ],
  "meta": { "total": 12, "current_page": 1, "last_page": 1, "per_page": 15 }
}

status filters the page that was fetched, so a filtered page can hold fewer episodes than per_page. Check meta.last_page for more pages.

See The Episode Object.

The Program Object ​

FieldMeaning
id, name, slugThe program's ID, name and slug
synopsisIts synopsis
banner_url, trailer_urlIts banner image and trailer HLS link, or null
typelive or on_demand
statusactive or paused
available_on_demandWhether episodes are kept available after they air
episodes_countHow many episodes it has. Only on the programs list
scheduleIts weekly slots: day_of_week (0 is Sunday), day, start_time and duration_minutes

The Episode Object ​

FieldMeaning
id, episode_number, name, synopsisThe episode's details
banner_url, trailer_urlThe episode's own banner and trailer, or null. They don't fall back to the program's
typepre_recorded or live
statusdraft, scheduled, on_air, completed, missed or cancelled
available_on_demandWhether the program keeps episodes available after they air
on_demandThe episode's playable video (id, duration, hls_url, thumbnail_url) once it's available, otherwise null
broadcastsThe episode's airings. See The Airing Object

The Airing Object ​

FieldMeaning
idThe airing's ID
program, episodeThe program and episode
starts_at, ends_atThe slot's start and end
start_time, duration_minutesThe start as HH:MM, and the length
episode_typepre_recorded or live
stateupcoming; pre_show (starts within 15 minutes); on_air; ended; missed (a live episode that never received a feed); or cancelled
went_live_atWhen a live feed first arrived, or null
banner_urlThe image to show: the episode's banner, the program's, or the channel's show banner