Interactive Live API reference
Interactive Live API reference
All endpoints take an environment scoped API key in the X-Api-Key header, and all of them are on the public API at https://api.antcdn.net.
Everything the AntCDN dashboard can do is here. If you run your own dashboard and your own player, you are not missing anything.
Note
The stream must have been created with interactive set to true. Questions on a stream that did not opt in are rejected.
Create an interactive stream
/v1/live-streams
{ "name": "Launch stream", "interactive": true, "recording": true}| Field | Type | Default | Meaning |
|---|---|---|---|
interactive | boolean | false | Opt in to Interactive Live Streaming. Cannot be changed later. |
The other fields are the same as any live stream. See Live streaming API.
Ask a question
/v1/live-streams/{streamId}/questions
{ "prompt": "Which build should we ship first?", "options": ["The rewrite", "The patch"], "allowFreeText": false}| Field | Type | Rules |
|---|---|---|
prompt | string | Required. Up to 500 characters. |
options | string[] | Required. Between 2 and 6 entries. |
allowFreeText | boolean | Optional. Lets viewers write an answer as well. |
Response:
{ "questionId": "lsq_71c4a9", "offsetSeconds": 412}offsetSeconds is where the question sits in the broadcast. A recording replays it at the same point.
The stream must be live. Asking a question of a stream that is not broadcasting is rejected, because the offset would be meaningless and viewers would have nothing to be looking at.
Asking a new question closes the one before it.
Close a question
/v1/live-streams/{streamId}/questions/{questionId}/close
No body. Response:
{ "questionId": "lsq_71c4a9", "counts": [1204, 388], "total": 1592}counts lines up with the options array you sent when you asked. Closing is safe to retry. Closing a question that is already closed keeps the original closing time.
List questions
/v1/live-streams/{streamId}/questions
Returns every question asked during the stream, in the order they were asked. This is the timeline a recording replays.
{ "questions": [ { "id": "lsq_71c4a9", "prompt": "Which build should we ship first?", "options": ["The rewrite", "The patch"], "offsetSeconds": 412, "allowFreeText": false, "counts": [1204, 388], "replayCounts": [51, 12] } ]}| Field | Meaning |
|---|---|
offsetSeconds | Seconds from the start of the broadcast. |
allowFreeText | Whether viewers could write an answer. |
counts | What the live audience answered. Present once the question has closed. |
replayCounts | What people watching the recording have answered. |
counts and replayCounts are kept apart on purpose and are never added together.
Read written answers
/v1/live-streams/{streamId}/questions/{questionId}/responses
{ "responses": [ { "questionId": "lsq_71c4a9", "body": "the rewrite, the patch will rot", "source": "live", "answeredAt": "2026-09-11T13:04:22Z" } ]}Newest first. source is live for what the broadcast audience wrote and replay for what people watching the recording wrote.
The viewer’s session id is deliberately not returned. It is stored so that a person cannot answer twice, not so that a broadcaster can follow one anonymous viewer around a stream.
Record a replay answer
/v1/live-streams/{streamId}/questions/{questionId}/replay-answer
For answers from people watching a recording. Use this if you serve recordings through your own system rather than using the SDK.
{ "sessionId": "sess_2f81c0", "optionIndex": 1, "text": "because the rewrite is cleaner"}| Field | Type | Rules |
|---|---|---|
sessionId | string | Required. Identifies the viewer. Anonymous and supplied by you. |
optionIndex | number | Required. The chosen option, or -1 to answer in writing only. |
text | string | Optional. Up to 280 characters. Only accepted if the question allows written answers. |
Response:
{ "recorded": true }recorded is false when this session had already answered. That is not an error. A viewer whose connection retried the submission should be told it worked.
Caution
Answers are deduplicated by sessionId, which your own system supplies. Use a session id your backend controls rather than one a browser can freely choose, if replay results matter to you.
Viewer endpoints
These are on the delivery edge at https://worker.antcdn.net, not the API. They are public, because viewers are anonymous members of the audience and hold no key.
Join a room
/v1/{streamId}/live-room?sessionId={sessionId}
A websocket upgrade. The SDK does this for you. See the Player SDK if you would rather implement the protocol yourself.
Read the viewer count
/v1/{streamId}/live-room/count
{ "viewerCount": 12480 }A cheap read for a dashboard, with no socket needed.
Limits
| Limit | Value |
|---|---|
| Options per question | 2 to 6 |
| Prompt length | 500 characters |
| Written answer length | 280 characters |
| Questions open at once | 1 |
| Answers per viewer per question | 1 |
| Concurrent viewers per room | more than 200,000 |