API Reference
Overview
Conventions shared by every endpoint — transport, the request cycle, and how a session is acquired.
Conventions
| Base path | /v1 |
| Method | POST on every endpoint — there are no GET routes |
| Request body | JSON, Content-Type: application/json |
| Response body | JSON |
| CORS | Enabled on all routes, so browsers may call the API directly |
| Auth | None. The server holds no credentials of its own |
Request bodies are decoded with a schema at the boundary. A body that does not
match returns 400 INVALID_REQUEST with the validation message.
The endpoints
| Endpoint | Purpose |
|---|---|
POST /v1/sessions |
Bootstrap a chat: returns credentials and the first continuation token |
POST /v1/poll |
Exchange a token for messages and the next token |
POST /v1/probe |
Diagnose which innertube clients work for a video |
The request cycle
sessions is called once. poll is called repeatedly, each time with the token
returned by the previous call.
sessions ──> { apiKey, webVersion, client, endpoint, token, timeoutMs }
│
└──> poll ──> { messages, token, timeoutMs }
│
└──> poll ──> ... until token === nullBecause the server keeps nothing between requests, the four values apiKey,
webVersion, client and endpoint must be echoed back on every poll along
with the current token. Treat the session response as an opaque bundle you
carry forward.
What happens during a session bootstrap
Understanding this explains most of the error codes.
1. Resolve the video id
The input is accepted as a full URL or a bare id and reduced to an 11-character
id. Anything else fails with INVALID_VIDEO_ID.
2. Fetch innertube credentials
The server requests https://www.youtube.com/sw.js and extracts
INNERTUBE_API_KEY and INNERTUBE_CLIENT_VERSION from it. These are fetched
live for every session rather than hardcoded, because YouTube rotates them.
A failure here is SW_JS_FAILED.
3. Find the chat renderer
The server loads the popout chat page first
(/live_chat?is_popout=1&v=<id>) and falls back to the watch page
(/watch?v=<id>). From the HTML it brace-matches the ytInitialData JSON
object, then walks it looking for a liveChatRenderer (live) or
liveChatReplayRenderer (replay) that carries a continuation token. Which one
was found is reported back as chatType.
If neither page yields a renderer with a token, the result is NO_LIVE_CHAT —
the video is not live, has chat disabled, has no replay chat, or is
unavailable.
4. Pick a working client
A continuation token alone is not enough; it has to be redeemed against an
innertube client that YouTube will accept for this video. The server tries
WEB, then TVHTML5, and for each tries the get_live_chat endpoint before
get_live_chat_replay, stopping at the first combination that returns a
parseable response. That winning pair is what comes back as client and
endpoint.
If every combination fails, the result is NO_WORKING_CLIENT.
Reading YouTube's failures
YouTube returns HTTP 200 with an error object in the body when an innertube
call fails. The server treats such a response as a failure, not a success, and
surfaces it as UPSTREAM_ERROR. See Errors for the
complete list.