Getting started
What is Rundown Studio?Create an accountRundown
Rundown basicsColumnsTemplatesSettingsTrashCell historyMentionsText variablesRunning a showImport CSV rundownEvent
Event basicsSharing eventsAPI
Getting startedAPI reference ↗Build a rundown from CSVWorking with cell contentLive updates over SSEAdvanced usageError referenceMigrating from v0API v0 (deprecated)Integrations
Companion ModuleQLabSharing and outputs
Read-only rundownEditable rundownOutputPrompterPDF exportCSV exportAccount
Your teamSubscription and invoicesUpdates
ChangelogMigrating from v0
The v0 API is deprecated and shuts down on July 1, 2028. Here's the timeline and how every v0 call maps to v1.
The v0 API (/api-v0) keeps working until its sunset date, but it is frozen: no new features, fixes for critical issues only. Everything it does — and a lot it never did — is available on the v1 API.
Timeline
| Date | What happens |
|---|---|
| July 1, 2026 | v0 declared deprecated. It keeps working unchanged. |
| July 1, 2028 | v0 is shut down. Requests to /api-v0 stop working. |
You don’t have to take our word for it — every v0 response now carries the deprecation headers (RFC 9745 / RFC 8594):
Deprecation: @1782864000
Sunset: Sat, 01 Jul 2028 00:00:00 GMT
Link: <https://api-v1.rundownstudio.app/rundowns/abc123/status>; rel="successor-version"
The Link: …; rel="successor-version" header on each response points at the v1 endpoint that replaces the one you just called — your logs are a personalized migration checklist.
Before you start: mint a new token
v0 tokens do not work on v1. The two APIs use separate signing keys, so a v0 token sent to /api-v1 is rejected with 401 auth.invalid_token. Create a v1 token in the dashboard’s API section — and take the opportunity to scope it narrowly (see Getting started).
What changed conceptually
- Control actions are
POST, notGET. v0 triggeredstart/pause/nextwith bare GET URLs. In v1, reads areGETand actions arePOST— a prefetching proxy can never start your show by accident. The?token=query parameter still works on the whole control surface, so URL-only hardware (stream decks, cue triggers) just needs the method switched to POST for actions; status and countdown reads remain plain GETs. - A real data plane. v1 adds full CRUD over rundowns, cues, columns, and cells — v0 could read and control but barely write.
- One response envelope. Every success is
{ ok, message, data, meta }; every error is RFC 9457application/problem+jsonwith a stablecode. See the error reference. snake_caseon the wire. v0 mixed conventions; v1 is uniformlysnake_case(duration_ms,start_time,created_at).lockedis nowprevent_edits, and the API respects it: locked cues reject writes withcues.prevent_edits.
Endpoint mapping
All v0 paths below are relative to the v0 base (…/api-v0); v1 paths are relative to the v1 base (https://api-v1.rundownstudio.app), which is version-less.
Control
| v0 | v1 |
|---|---|
GET /rundown/:id/start | POST /rundowns/:id/action:start |
GET /rundown/:id/pause | POST /rundowns/:id/action:pause |
GET /rundown/:id/next | POST /rundowns/:id/action:next |
GET /rundown/:id/previous | POST /rundowns/:id/action:previous |
PUT /rundown/:id/cues/:cue_id/jump-to-cue | POST /rundowns/:id/action:jump |
GET /rundown/:id/cues/active/add | POST /rundowns/:id/action:adjust-duration |
GET /rundown/:id/cues/active/subtract | POST /rundowns/:id/action:adjust-duration |
GET /rundown/:id/cues/active | GET /rundowns/:id/status |
GET /rundown/:id/cues/next | GET /rundowns/:id/status |
The status snapshot carries the active cue, the next cue, the show state, and the timestamps to compute a local countdown — one call replaces several v0 reads. There’s also GET /rundowns/:id/countdown if you’d rather have the server do the clock math.
Output message
| v0 | v1 |
|---|---|
PATCH /rundown/:id/output-message | PATCH /rundowns/:id/output-message |
POST /rundown/:id/output-message/show | PATCH /rundowns/:id/output-message with { "visible": true } |
POST /rundown/:id/output-message/hide | PATCH /rundowns/:id/output-message with { "visible": false } |
POST /rundown/:id/output-message/toggle | No direct successor — GET the message, then PATCH the flipped visible value |
Data reads and writes
| v0 | v1 |
|---|---|
GET /rundown/:id | GET /rundowns/:id |
GET /rundown/:id/cues | GET /rundowns/:id/cues |
GET /rundown/:id/cues/:cue_id | GET /rundowns/:id/cues/:cue_id |
PATCH /rundown/:id/cues/:cue_id | PATCH /rundowns/:id/cues/:cue_id |
GET /rundown/:id/columns | GET /rundowns/:id/columns |
GET /rundown/:id/columns/:column_id/cues-and-cells | GET /rundowns/:id/columns/:column_id/cells |
GET /rundown/:id/columns/:column_id/cells/active | GET /rundowns/:id/status for the active cue id, then GET /rundowns/:id/cells?cue_id=…&column_id=… |
GET /rundown/:id/export-csv | GET /rundowns/:id/export?format=csv |
GET /ping | GET /ping |
Mentions and text variables
| v0 | v1 |
|---|---|
GET / POST /rundown/:id/mentions | GET / POST /rundowns/:id/mentions |
PUT /rundown/:id/mentions (bulk) | POST /rundowns/:id/mentions:bulk |
PUT /rundown/:id/mentions/:id | PATCH /rundowns/:id/mentions/:id |
GET / DELETE /rundown/:id/mentions/:id | GET / DELETE /rundowns/:id/mentions/:id |
GET / POST /rundown/:id/text-variables | GET / POST /rundowns/:id/text-variables |
PUT or PATCH /rundown/:id/text-variables (bulk) | POST /rundowns/:id/text-variables:bulk |
PUT /rundown/:id/text-variables/:key | PATCH /rundowns/:id/text-variables/:key |
GET / DELETE /rundown/:id/text-variables/:key | GET / DELETE /rundowns/:id/text-variables/:key |
The websocket gap
v0 has a socket.io push channel; v1 ships without one. The v1 pattern is: poll GET /rundowns/:id/status (at most about once every 5 seconds), and compute the ticking countdown locally from the snapshot’s timestamps — the response is designed so a poll-and-local-clock client stays perfectly in sync. See Getting started for the formulas.
If your integration genuinely depends on push (you need to react to cue changes with sub-second latency, not display a clock), you can keep using the v0 socket until sunset — it keeps working until July 1, 2028. A proper push channel (WebSocket, with webhooks) is queued as a v1 follow-up and will emit the same status-snapshot shape; we expect it to ship well before the v0 sunset.
Rate limits
v0 allowed 60 requests per minute per team. v1 is 20/min on the free plan and 120/min on paid plans, also per team, with the same RateLimit-* headers. If you’re on the free plan and polling aggressively, slow your poll loop or compute more locally between polls.
Where to go next
- Getting started — token, first request, auth model.
- Build a rundown from CSV — v1’s import surface, which v0 never had.
- API reference — every v1 endpoint in detail.