Authentication

API keys, rate limits, and playback tokens: the three credential types the API uses.

API keys

Create and revoke API keys from Settings in your dashboard. A new key's plaintext value is shown exactly once, right after you create it. vdoX only stores its hash, so if you lose it, revoke it and create a new one, there's no way to view it again.

  • Keys look like vdx_ followed by 40 hex characters (44 characters total).
  • Revoking a key is immediate and takes effect on its next use.
  • Every key in a workspace can do everything the API supports; there are no scoped/read-only keys yet.

Send it in the standard bearer header on every request:

Header
Authorization: Bearer vdx_4f2b9e1a7c6d3f805e2b91ac4d7e0f3b1a2c9d8e

A missing header, the wrong scheme, or an unknown/revoked key all return the same 401, so a caller can't probe which one is wrong:

jsonResponse, 401
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or missing API key"
  }
}

Rate limits

Each workspace gets 60 requests per minute, shared across every API key in that workspace. Every authenticated response, success or error, carries an X-RateLimit-Remaining header showing how many requests are left in the current window.

Go over the limit and you get a 429 instead of the request running:

jsonResponse, 429
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded, try again later"
  }
}

Playback tokens

Playback tokens are a separate, short-lived credential: your backend mints one per viewer, per video, by calling POST /api/v1/videos/:id/playback-token with your API key. Unlike an API key, a playback token can only play the one video it was minted for, and only for a few minutes.

jsonResponse, 200
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlb0lkIjoiMDFBUlozTkRFS1RTVjRSUkZGUTY5RzVGQVYi...",
  "expiresAt": "2026-07-13T09:05:00.000Z",
  "manifestUrl": "https://api.vdox.example.com/videos/01ARZ3NDEKTSV4RRFFQ69G5FAV/hls/master.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

expiresAt is 5 minutes (300 seconds) after minting by default. Mint a fresh token per view, don't try to reuse one across viewers or cache it long-term.

Errors

Every error response has the same shape: { error: { code, message } }. The full set of codes the API returns:

CodeHTTP statusMeaning
unauthorized401Missing, malformed, or revoked API key
rate_limited429More than 60 requests in the last 60 seconds for this workspace
invalid_request400Request body or query params failed validation
invalid_file400Filename extension isn't one of mp4, mov, mkv, webm, m4v
not_found404Video doesn't exist, or belongs to a different workspace
not_ready409Video hasn't finished processing yet
conflict409Video isn't in a state the request allows (e.g. cancelling one that's already ready)
workspace_suspended403Workspace has been suspended by an admin, contact support
quota_videos403Your plan's video limit is reached
quota_storage403Your plan's storage limit is reached
quota_upload_size403File exceeds the plan's max upload size
quota_plays403Plan's monthly plays limit reached
unsupported_file422The uploaded file was rejected during processing
upstream_error502vdoX's processing service is temporarily unavailable, retry
internal_error500Unexpected server error