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 URL | https://stream.cecula.com/api |
| Authentication | None. The endpoints are public and read-only. Anyone with your channel's ID can read them, so treat the data as published |
| Method | GET |
| Browsers | Cross-origin requests are allowed, so you can call the API straight from a web page |
| Format | JSON. Times are ISO 8601 |
| Channel ID | Use 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:
{ "error": "Channel not found" }Endpoints at a Glance
| Endpoint | Returns |
|---|---|
GET /channels/{uuid}/status | What's playing now. See Now Playing |
GET /channels/{uuid}/schedule | Recent and upcoming scheduled broadcasts. See Scheduled Broadcasts |
GET /channels/{uuid}/catchups | Catchup entries, with playback links. See Catchup |
GET /channels/{channel}/programs | The channel's programs. See Programs |
GET /channels/{channel}/programs/current | The program episode on air now. See Program On Air Now |
GET /channels/{channel}/programs/next | The next airing. See Next and Upcoming Airings |
GET /channels/{channel}/programs/upcoming | Upcoming airings. See Next and Upcoming Airings |
GET /programs/{program}/episodes | A program's episodes. See Program Episodes |
Now Playing
GET /channels/{uuid}/statusReturns what the channel is showing at this moment.
{
"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"
}| Field | Meaning |
|---|---|
channel_name | The channel's name |
is_live | true while a live feed is on air |
current_video | What's playing, or null if nothing is |
current_video.id | The video's ID. Only for scheduled broadcasts |
current_video.name, description, location | Details of what's playing |
current_video.thumbnail | An image for it, or null |
current_video.start_time, end_time | When it started and ends. null for a live broadcast |
current_video.remaining_time | Seconds left |
current_video.remaining_time_human | Time left as MM:SS or HH:MM:SS, or Live |
estimated_end_at | When this answer is expected to change |
current_video describes the first of these that applies:
- A program episode in its slot: the episode's name and synopsis (or the program's), its banner, and the slot's times.
- A scheduled broadcast: the video's details and the broadcast's times.
- A live broadcast: your live event title, description, location and show banner. The times are
null, andremaining_time_humanisLive. - 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}/scheduleReturns 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.
{
"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"
}
}
]
}| Field | Meaning |
|---|---|
schedule_count | How many broadcasts are returned |
schedule[].id | The broadcast's ID |
schedule[].start_time, end_time | The broadcast's times, in UTC (ending in Z) |
schedule[].status | pending, live, completed or cancelled |
schedule[].video | The video's name, description and thumbnail |
Catchup
GET /channels/{uuid}/catchups?page=1Returns Catchup entries, newest air time first, 15 per page. Add ?page=2 and so on for more.
{
"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"
}
}
]
}| Field | Meaning |
|---|---|
catchup_count | The total number of entries |
current_page, last_page, per_page | Paging details |
catchups[].title, description | The entry's title and description |
catchups[].start_time, end_time | When it aired, in UTC |
catchups[].duration | Length in seconds |
catchups[].video.hls_url | The link to play it in an HLS player |
catchups[].video.thumbnail, resolution | Its image and resolution |
Programs
GET /channels/{channel}/programsReturns the channel's active and paused programs, in name order. Draft and archived programs are never included.
| Parameter | Meaning |
|---|---|
status | active or paused |
type | live or on_demand |
per_page | Programs per page. Defaults to 15, up to 50 |
{
"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/currentReturns the program episode whose slot is open now. It's safe to call on any channel, including one with no programs.
{
"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_source | What viewers are getting |
|---|---|
livestream | The live feed |
pre_recorded | The pre-recorded episode |
trailer | The trailer, while a live episode waits for its feed |
standby | The starts soon card, while a live episode waits for its feed |
fallback | The channel's usual content, because nothing else is available |
When no slot is open, status is off_air and the other fields are null:
{
"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/nextReturns the soonest airing still to come, under next, or null if nothing is booked.
{
"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/upcomingReturns upcoming airings, soonest first, under upcoming, with a count. An episode on air now is included at the top.
| Parameter | Meaning |
|---|---|
limit | How many airings. Defaults to 10, up to 50 |
from | Only airings at or after this time. Defaults to now |
to | Only 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}/episodesReturns a program's episodes, highest episode number first. It works for active and paused programs.
| Parameter | Meaning |
|---|---|
status | draft, scheduled, on_air, completed, missed or cancelled |
from | Only episodes with an airing at or after this time |
to | Only episodes with an airing at or before this time |
per_page | Episodes per page. Defaults to 15, up to 50 |
{
"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
| Field | Meaning |
|---|---|
id, name, slug | The program's ID, name and slug |
synopsis | Its synopsis |
banner_url, trailer_url | Its banner image and trailer HLS link, or null |
type | live or on_demand |
status | active or paused |
available_on_demand | Whether episodes are kept available after they air |
episodes_count | How many episodes it has. Only on the programs list |
schedule | Its weekly slots: day_of_week (0 is Sunday), day, start_time and duration_minutes |
The Episode Object
| Field | Meaning |
|---|---|
id, episode_number, name, synopsis | The episode's details |
banner_url, trailer_url | The episode's own banner and trailer, or null. They don't fall back to the program's |
type | pre_recorded or live |
status | draft, scheduled, on_air, completed, missed or cancelled |
available_on_demand | Whether the program keeps episodes available after they air |
on_demand | The episode's playable video (id, duration, hls_url, thumbnail_url) once it's available, otherwise null |
broadcasts | The episode's airings. See The Airing Object |
The Airing Object
| Field | Meaning |
|---|---|
id | The airing's ID |
program, episode | The program and episode |
starts_at, ends_at | The slot's start and end |
start_time, duration_minutes | The start as HH:MM, and the length |
episode_type | pre_recorded or live |
state | upcoming; pre_show (starts within 15 minutes); on_air; ended; missed (a live episode that never received a feed); or cancelled |
went_live_at | When a live feed first arrived, or null |
banner_url | The image to show: the episode's banner, the program's, or the channel's show banner |

