API reference
Errors & rate limits
Error format
Every error response has the same shape:
{ "error": { "code": "rate_limited", "message": "Too many requests. Limit: 100/min." } }
| HTTP | Code | Meaning | Fix |
|---|---|---|---|
| 400 | missing_fields | Required body/query params absent. | Check the endpoint reference. |
| 400 | invalid_fields | Field validation failed (e.g. bad platform, script too long, duration out of range). | Check the endpoint reference for constraints. |
| 400 | invalid_creator | The creator_id doesn't match any creator. | Use GET /api/v1/creators to list available creators. |
| 400 | invalid_url | Webhook url failed validation (must be an https:// endpoint). | Check the URL and re-register. |
| 400 | invalid_events | Webhook events must be a non-empty subset of stream.started, stream.ended, stream.error. | Fix the event list. |
| 401 | unauthorized | Key missing, malformed, or revoked. GET /creators needs no key, but if you send one that doesn't validate it also returns 401. | Verify the Bearer tt_… header; create a new key if revoked. |
| 402 | plan_required | Creating a live key, or managing streams and webhooks with one, requires the Growth plan or above. Test keys are free. | Upgrade your plan or use a test key. |
| 402 | no_minutes | Starting a live stream when the minutes you've used this billing period, plus time on streams running now, have reached your plan's allowance. | Wait for your next billing period or upgrade under Settings → Billing. |
| 403 | insufficient_scope | Key lacks the scope for this endpoint. | Create a key with the needed scope. |
| 403 | vertical_mismatch | vertical in the request ≠ your brand's vertical, or platform is not permitted for your brand's vertical. | Drop the vertical field (it defaults to your brand). |
| 403 | vertical_locked | The key was created when your brand had a different vertical than it has now, so it no longer works. | Create a new key. |
| 404 | not_found | Resource doesn't exist or belongs to another brand. Ending a stream that isn't live also returns this, and so does a test key reading or ending a stream that wasn't started with a test key. | Check the id, or wait for the stream to be live before ending it. |
| 409 | webhook_limit | Your brand already has 10 active webhooks. | Delete one you no longer use (DELETE /api/v1/webhooks?id=…), then register again. |
| 429 | rate_limited | Over the per-minute request limit. | Back off before retrying. |
| 429 | concurrency_limit | Brand already has 3 active (preparing+live) streams of the same kind. Test-key and live-key streams are counted separately. | End one before starting another. |
| 500 | db_error | Something failed on our side. | Retry with backoff; contact support if persistent. |
| 502 | launch_failed | Stream dispatch to the agent worker failed. | Retry — this is usually transient. If persistent, contact support. |
| 502 | stop_failed | DELETE /streams/{id} couldn't confirm the broadcast stopped. The stream stays live. | Retry the DELETE. If persistent, contact support. |
Warnings
A successful response can carry a warnings array: the request worked, but
something needs your attention.
| Code | Returned by | Meaning | Fix |
|---|---|---|---|
no_broadcast_destination | POST /streams (live keys) | The stream started, but your brand has no connected channel with a stream key, so it reaches no platform. | Connect a channel, then start a new stream. |
Rate limits
| Limit | Applies to |
|---|---|
| 100 requests/min | All v1 endpoints except public GET /creators |
| 10 active webhooks | Per brand. The 11th returns 409 webhook_limit. |
| 1,000 waiting webhook deliveries | Per brand, including retries. Above it, new events are not queued until the backlog drains. |
The limit is per brand, per minute, fixed window. When you hit it you'll get a 429 rate_limited. GET /api/v1/creators is public and not rate-limited. 429 concurrency_limit is separate — retrying won't clear it, end a stream first.
Limits are applied in-memory and reset on deploy. If you're polling stream status, switch to webhooks — it's what they're for.
Idempotency & retries
GET/DELETEare safe to retry freely.POST /streamssupports anIdempotency-Keyheader (recommended). Send a unique key per logical request (e.g. a UUID). If the request times out or the connection drops, retry with the same key and the same body:- same key + same body ⇒ the exact original response is replayed — never a second stream or a second charge
- same key + different body ⇒
409 idempotency_conflict - same key while the first request is still executing ⇒
409 idempotency_in_progress; keep retrying with the same key - if the idempotency ledger is temporarily unavailable, the POST fails
closed with
503 idempotency_unavailable(no stream is started); retry with the same key - successful responses replay for 24 hours; failed launches (502) replay for 1 hour, then the key is free again
- Without the header, a retry can create a duplicate stream — if you don't
send one, check
GET /streamsbefore retrying. - Webhook deliveries are at-least-once; dedupe on the event
id.
Abuse prevention
Keys used for probing, scraping, or exceeding rate limits without prior arrangement may be revoked. If you need higher limits, email us — we're happy to accommodate legitimate traffic.
Was this page helpful?