Skip to main content
The Cue API is a small, predictable REST API over HTTPS. Everything speaks JSON and every call authenticates with an API key. There are five workflows, and each has a guide page with worked examples: Three of the five take a video, so there’s one more group underneath them: POST /v1/videos · POST /v1/videos/{id}/ingest · GET /v1/videos/{id}. Analysis is billed there, once, per minute of the clip. The resulting video_id is reused by every match, sync and loop against it. Beats stands apart: it takes audio you point us at, never a video_id, and it has its own queue, worker and meter.

Base URL

All endpoints live under /v1. There’s no separate sandbox host and no sandbox mode: customer keys are always vbsk_live_, and every call is billed at the rates in Metering & pricing. See Authentication.

Authentication

Every request carries your API key, either way round. Use whichever your client reaches for:
The same key authenticates the MCP server, where Bearer is what most clients ask for by default. See Authentication for rotation and revocation.

Conventions

JSON in, JSON out

Send content-type: application/json. Every response is JSON, success or error.

Stable IDs

A video_id is yours to reuse across match, sync, and loop. A track_id (from a match) resolves in your catalog.

Request IDs

Every response carries X-Request-Id. Include it when you contact support.

Timings, not recordings

Responses carry catalog identifiers and analysis. No audio is attached by default. See Preview audio.

Expand

?expand=full on a match or underscore returns the full track object and the lane’s candidate pool instead of the lean shape.

Idempotency

Idempotency-Key is accepted on five endpoints, and it does two different things depending on which one you send it to. On POST /v1/beats it is a true idempotency key: a repeat with the same key returns the original job_id and starts no second job, a key is honoured for 24 hours, and reusing one for a different request is a 422. On POST /v1/match, /v1/underscore, /v1/align and /v1/loop it only suppresses a duplicate row in the billing ledger. The request itself re-executes in full and you get a freshly computed response, so a retry is safe on your bill but is not free of work. Send a new key per distinct request and reuse a key only when retrying that exact request. A key you pin across different calls will silently suppress the billing for all of them. POST /v1/videos and POST /v1/videos/{id}/ingest do not accept the header at all. Those are the calls that trigger the per-minute analysis charge, and the meter dedupes them on a server-generated key of its own.

Synchronous vs. async

Work that’s already warm returns 200 immediately. Work that needs a first-time build returns 202, so a long build never trips a request timeout. There are two 202 shapes and they are not interchangeable. A job carries a job_id and a job URL. That covers a match on a video whose analysis isn’t cached, a cold align, a cold loop, and any beats call:
202
A video that is still being ingested carries no job_id at all, and points at the video:
202
POST /v1/videos, and POST /v1/match called with a video_url, both return that second shape. Branch on whether job_id is present rather than on the status code, and follow the poll path you were actually given. Poll until status is complete. Jobs are billed once, on completion, and polling is free. Each family has its own job endpoint: GET /v1/match/jobs/{id}, /v1/align/jobs/{id}, /v1/loop/jobs/{id}, /v1/beats/{job_id}.

Errors & rate limits

Every /v1 error returns a JSON error object with a stable type, a human-readable message and the request_id for that call. A 422 from request validation adds a details array. Keys are rate limited per key, 60 requests per minute by default. See Errors & rate limits for the full table.

Endpoints

Pick any endpoint from the sidebar for its parameters, schema, and a live Try it panel. The workflow table at the top of this page maps each one to the guide that shows it in use. The reference covers every endpoint you can call with an API key. Two /v1 routes are left out because you can’t: the Stripe webhooks, which authenticate by signature rather than by key. Prefer an agent to writing HTTP? The same surface is available over MCP, where each tool wraps one endpoint and bills identically.