TwinToneAPI Docs

API reference

Streams

Programmatic control of AI-hosted live streams.

MethodPathScope
POST/api/v1/streamsstreams:write
GET/api/v1/streamsstreams:read
GET/api/v1/streams/{id}streams:read
DELETE/api/v1/streams/{id}streams:write

Stream lifecycle

preparing → live → ended ↘ error Preparing streams that can't dispatch within 5 minutes automatically transition to error. `preparing` time never consumes plan minutes.
StatusMeaningFields populated
preparingStream created, agent is being dispatched to the room.stream_id, room_name, created_at
liveAvatar is streaming to the platform. From here a live-key stream counts its full booked duration_minutes against your plan.+ started_at, viewer_count (live-updating)
endedStream finished (via DELETE, the agent, or the platform). Ending early does not give booked minutes back.+ ended_at, final viewer_count
errorSomething failed during dispatch or streaming. See the status field for details.+ ended_at

Stuck preparing: if the agent worker can't join within 5 minutes, the stream transitions to error and a stream.error webhook fires (if registered). preparing time never consumes plan minutes.


Start a stream

POST /api/v1/streams

Request body

FieldTypeRequiredNotes
creator_idstring✅Creator to host (use GET /api/v1/creators to list available creators).
product_namestring✅Product/game being featured.
platformstring✅youtube, tiktok, twitch, facebook, instagram.
duration_minutesnumber✅ live / – testHow long to stream (1–480 minutes). Required for live keys. Once the stream goes live, this booked duration is what counts against your plan minutes, even if you end it early. Omit with test keys — they return live immediately.
scriptstring–Talking points / script seed for the host.
verticalstring–Must match your brand's configured vertical.

Response 201 Created

{ "stream_id": "a1b2c3d4-e5f6-…", // ← save this — you'll need it to poll/end "status": "live", "room_name": "stream-a1b2c3d4", "ws_url": "wss://rt.twintone.ai/v1/rooms/stream-a1b2c3d4", "viewer_token": null, "created_at": "2026-08-07T10:00:00.000Z" }

status matches the stream's stored status: a live-key stream is live once the agent has been dispatched, and stream.started fires at the same moment.

Test keys: with tt_test_… the stream also returns status: "live" (plus "test": true, ws_url: null) — no agent dispatch, no minutes consumed — so you can build the full lifecycle integration, including DELETE, without a real stream.

No connected channel: a live-key stream for a brand with no connected channel that has a stream key still starts, but reaches no platform. The 201 response then includes "warnings": [{ "code": "no_broadcast_destination", "message": "…" }]. Connect a channel and start a new stream.

Errors: 400 missing_fields · 400 invalid_fields · 400 invalid_creator · 401 unauthorized · 402 plan_required · 402 no_minutes · 403 vertical_mismatch · 429 rate_limited · 429 concurrency_limit · 502 launch_failed


List streams

GET /api/v1/streams?status=live&limit=20&offset=0

ParamDefaultNotes
statusallFilter: preparing, live, ended, error.
limit20Max 100.
offset0For pagination.

Response 200

{ "streams": [ { "id": "…", "status": "live", "platform": "youtube", … } ], "total": 47, "limit": 20, "offset": 0 }

Results are newest-first and scoped to your brand. With a test key, only streams started with a test key are listed, and total counts only those.


Get a stream

GET /api/v1/streams/{id}

Response 200

{ "stream_id": "a1b2c3d4-…", "status": "live", "creator_id": "avt_9ww075quzedr", // ← the creator you picked "product_name": "Radiance Serum", // ← YOUR product name "platform": "youtube", "vertical": "live-commerce", "viewer_count": 312, "started_at": "2026-08-07T10:00:14.000Z", "ended_at": null, "room_name": "stream-a1b2c3d4", "events": [] }

404 if the stream doesn't exist or belongs to another brand. A test key also gets 404 for a stream that wasn't started with a test key.

Note: the events field is currently empty (reserved for future telemetry events).


End a stream

DELETE /api/v1/streams/{id}

Ends a live stream immediately. For a live-key stream this stops the broadcast on every platform first, then marks the stream ended. Test-key streams have no broadcast, so they are just marked ended.

Response 200

{ "stream_id": "a1b2c3d4-…", "status": "ended", "ended_at": "2026-08-07T11:30:00.000Z" }

404 if the stream isn't found or isn't live. A test key can only end streams started with a test key, so it gets 404 for any other stream and that stream keeps running.

502 stop_failed if we couldn't confirm the broadcast stopped. The stream stays live; retry the request.

Was this page helpful?