Errors and limits
Error format
Every non-2xx response is shaped as:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description.",
"field": "optional — name of the offending input field for 4xx"
}
}Always present alongside the body: X-DCAST-Request-Id response header. Quote it in any support ticket so we can grep the exact request lifecycle.
Error codes
| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | No API key sent |
INVALID_KEY_FORMAT | 401 | The key does not start with pk_ |
INVALID_KEY / KEY_DISABLED / KEY_EXPIRED | 401 | Unknown, revoked or expired key |
INVALID_USER_TOKEN | 401 | X-User-Token present but invalid, expired, or for a different user than the key owner |
INSUFFICIENT_SCOPE | 403 | The key's scope does not allow this HTTP method (e.g. a READ_ONLY key sending a write) |
PERMISSION_DENIED | 403 | The key lacks a required permission (e.g. videos:write) |
FINANCIAL_SCOPE_REQUIRED | 403 | Money endpoint called without FULL_ACCESS or a finance:* permission |
OWNER_SCOPE_REQUIRED | 403 | Minting a key, or revoking another key, without a FULL_ACCESS key or X-User-Token |
EMAIL_NOT_VERIFIED | 403 | The account's email address is not verified yet |
IP_NOT_ALLOWED / DOMAIN_NOT_ALLOWED | 403 | The key is restricted to other IPs / domains |
ADMIN_ONLY | 403 | Admin-gated endpoint called with a creator key |
integration_domain_required / origin_not_allowed | 403 | Checkout origin lock. The body is { "success": false, "error": "<code>" } (a string, not an object). See Domain verification. |
METHOD_NOT_ALLOWED | 405 | The path exists but not with this method; see the Allow header |
CATALOG_DISABLED | 410 | /search, /trending, /feed are withdrawn |
NOT_FOUND | 404 | Resource not found (also returned for foreign resources — we never leak existence) |
BAD_REQUEST | 400 | Invalid parameters. error.field names the offending input. |
INVALID_IDEMPOTENCY_KEY | 400 | Idempotency-Key format failed [A-Za-z0-9_-]{8,255} |
IDEMPOTENCY_IN_FLIGHT | 409 | A prior request with this Idempotency-Key is still being processed |
IDEMPOTENCY_KEY_REUSE | 422 | Same Idempotency-Key was used with a different body |
RATE_LIMITED | 429 | Per-key rate limit exceeded (also the per-endpoint caps on chat posts, subscriber adds and login/register). See Retry-After + X-RateLimit-Reset for when to retry. |
RATE_LIMIT | 429 | Only on POST /videos/:id/views: too many view events from one IP for one video |
SSE_PER_KEY_CAP | 429 | Too many concurrent SSE tails (chat / status / viewers) on one key |
QUOTA_EXCEEDED | 403 | Storage or plan limit exceeded |
INTERNAL_ERROR | 500 | Server error. The X-DCAST-Request-Id identifies it in our logs. |
The code on a key-level rate limit is RATE_LIMITED; RATE_LIMIT_EXCEEDED is never returned. One exception to the envelope: the per-IP limiters on POST /auth/login, POST /auth/register, /channel/* and /videos/:id/related answer 429 with { "success": false, "error": "Too many requests", "retryAfter": <seconds> }.
Rate limit headers
Every response to a request whose key passed authentication (including later 4xx and 5xx) carries the headers below; a 401/403 from the key check itself carries none:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current 60-second window for your pk_* key. |
X-RateLimit-Remaining | Requests left in this window. Reaches 0 when the next request would 429. Value -1 = backend rate-limit storage temporarily unavailable; the request was allowed through, throttle conservatively. |
X-RateLimit-Reset | Unix epoch (seconds) when the current window closes and the counter resets. |
Retry-After | Only on 429. Seconds to wait before retrying. |
X-RateLimit-Daily-Limit, X-RateLimit-Daily-Remaining, X-RateLimit-Daily-Reset | Only on a key with a daily quota. Over the quota the answer is 429 DAILY_QUOTA_EXCEEDED; the quota resets at 00:00 UTC. |
Dcast-Key-Mode | live or test — the mode of the key that made the call (see Test mode). |
Limits are per-pk_* key. Each key has its own bucket and does not affect other keys. A key created in the dashboard (Settings → API Keys) defaults to 10000 req/min; a key minted with POST /me/api-keys gets 1000 req/min. Either may also carry an optional daily quota.
Soft-throttle on your side using X-RateLimit-Remaining — hitting 429 is recoverable, but hammering 429s wastes round-trips. Industry pattern: when Remaining < Limit * 0.1 back off for the rest of the window.
Per-endpoint rate limits (current overrides)
| Scope | Limit |
|---|---|
| General partner-API | The key's own per-minute limit (see above) |
POST /streams/:id/chat | 60 per minute per key per stream; 1000 per day per stream |
POST /subscribers, POST /users/:username/subscribe | 100 and 60 per hour per key respectively (429 RATE_LIMITED) |
/channel/*, /videos/:id/related (public) | 60 req/min per IP |
POST /videos/:id/views (public) | 30 req/min per IP |
POST /auth/login | 10 per 15 min per IP; 100 per hour per key |
POST /auth/register | 5 per 15 min per IP; 20 per hour per key |
| SSE tails per key (chat / status / viewers) | 25 concurrent connections per key |
File limits
- Video file: up to 100 GB
- Duration: up to 12 hours
- Uploaded-video resolution: up to 8K (4320p) (7680×4320) on VIP; the top rung is set by the plan — 720p Free, 1080p Star, 4K (2160p) Pro
- Live resolution: up to 4K (2160p) on VIP — 720p Free, 1080p Star, 2K (1440p) Pro. The live ladder is separate from the video ladder and is one rung lower on Pro.
- Frame rate: up to 120 fps for uploaded video, up to 60 fps live — identical on every plan, Free included. These are ceilings, not targets: a 25 fps source is delivered at 25 fps.
