LiveScript API
A WebSocket for live YouTube transcripts and a REST endpoint for non-live transcripts. All requests are authenticated with a Bearer API key.
Overview
The v1 API exposes two transcript surfaces: a WebSocket at /api/v1/live for currently-live YouTube videos, and a REST endpoint at /api/v1/transcript for videos that are no longer live. A usage endpoint reports remaining live minutes.
All responses are JSON. WebSocket messages are JSON-encoded text frames. Timestamps use ISO 8601; segment offsets use milliseconds.
Authentication
Every request requires an API key in the Authorization header. Keys are created in the dashboard and are shown only once at creation. Keys are prefixed with ls_live_.
Authorization: Bearer ls_live_xxxxxxxxxxxxxxxxFor the WebSocket endpoint, send the same header during the initial HTTP upgrade request. Missing or invalid keys return AUTHENTICATION_FAILED and close the socket.
Quickstart
Connect to the live WebSocket, send a subscribe message, and read transcript events.
// Node.js example using ws
import WebSocket from "ws";
const ws = new WebSocket("wss://livescript.live/api/v1/live", {
headers: { Authorization: `Bearer ${process.env.LIVESCRIPT_API_KEY}` },
});
ws.on("open", () => {
ws.send(JSON.stringify({
type: "subscribe",
source: "youtube",
source_id: "abc123DEF45",
language: "en",
delivery: "streaming",
}));
});
ws.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "transcript" && event.status === "final") {
console.log(event.text);
}
});Endpoints
| Method | Path | Description |
|---|---|---|
| WS | /api/v1/live | Subscribe to a live YouTube video and receive transcript events. |
| GET | /api/v1/transcript | Fetch transcript segments for a non-live YouTube video. |
| GET | /api/v1/usage | Return current period minute usage and remaining balance. |
Live WebSocket
Open a WebSocket to wss://livescript.live/api/v1/live and send a single subscribe message. The server streams transcript events until the video ends, you disconnect, or an error closes the socket. One subscribe message is allowed per socket.
Subscribe message
{
"type": "subscribe",
"source": "youtube",
"source_id": "abc123DEF45",
"language": "en",
"delivery": "streaming"
}| Field | Type | Required | Description |
|---|---|---|---|
| type | "subscribe" | yes | Message type. Must be "subscribe". |
| source | "youtube" | yes | Source platform. Only "youtube" is supported in v1. |
| source_id | string | yes | 11-character YouTube video ID. |
| language | "en" | "multi" | no | Transcript language. Defaults to "en". |
| delivery | "streaming" | "final" | no | "streaming" emits interim and final events; "final" emits stable text only. Defaults to "streaming". |
Transcript events
A transcript segment has a stable segment_id. While status is "interim", the text may be revised; each revision increments revision. The final revision has status: "final" and is stable.
Interim revision
{
"type": "transcript",
"source": "youtube",
"source_id": "abc123DEF45",
"segment_id": "seg_8KQ2m",
"revision": 2,
"text": "good bring",
"start_ms": 124000,
"end_ms": 125200,
"status": "interim"
}Final segment
{
"type": "transcript",
"source": "youtube",
"source_id": "abc123DEF45",
"segment_id": "seg_8KQ2m",
"revision": 3,
"text": "Good morning.",
"start_ms": 124000,
"end_ms": 125700,
"status": "final"
}| Field | Type | Required | Description |
|---|---|---|---|
| type | "transcript" | yes | Event type. |
| source | "youtube" | yes | Source platform. |
| source_id | string | yes | YouTube video ID. |
| segment_id | string | yes | Stable ID for the segment. Interim updates share the same segment_id. |
| revision | number | yes | Monotonic revision counter for a segment_id. Replace prior text on a higher revision. |
| text | string | yes | Transcript text for this segment. |
| start_ms | number | yes | Segment start, in milliseconds from the stream's origin. |
| end_ms | number | yes | Segment end, in milliseconds. |
| status | "interim" | "final" | yes | "interim" segments may be revised; "final" segments are stable. |
With delivery: "final", the server omits interim revisions and only emits the final segment.
GET /api/v1/transcript
Fetch the transcript of a YouTube video that is no longer live. Returns 404 if the video has no available transcript and 409 if the video is currently live (use the WebSocket instead).
GET https://livescript.live/api/v1/transcript?source=youtube&source_id=abc123DEF45
Authorization: Bearer ls_live_xxxResponse
{
"source": "youtube",
"source_id": "abc123DEF45",
"title": "Stream title",
"transcript": [
{
"segment_id": "cap_1",
"start_ms": 0,
"text": "Welcome back to the show.",
"status": "final"
},
{
"segment_id": "cap_2",
"start_ms": 4200,
"text": "Today we're covering the markets.",
"status": "final"
}
]
}| Query parameter | Required | Description |
|---|---|---|
| source | yes | Must be "youtube". |
| source_id | yes | 11-character YouTube video ID. |
GET /api/v1/usage
Returns the authenticated account's minute consumption for the current period. Usage is measured in connected live minutes. Non-live transcript fetches do not consume live minutes.
{
"plan": "pro",
"period_ends_at": "2026-06-22T00:00:00Z",
"live_minutes": {
"included_total": 1500,
"included_remaining": 420,
"topup_remaining": 900,
"total_remaining": 1320
},
"limits": {
"concurrent_live_streams": 1
}
}Errors
Errors are returned as a JSON object with a stable code and a human-readable message. On the WebSocket, an error frame is sent immediately before the socket is closed.
{
"type": "error",
"code": "SOURCE_NOT_LIVE",
"message": "The requested YouTube video is not currently live."
}| Code | Meaning |
|---|---|
| AUTHENTICATION_FAILED | The API key is missing, invalid, expired, or not allowed to use the live API. |
| SOURCE_NOT_LIVE | The requested YouTube video exists but is not currently live. |
| SOURCE_UNAVAILABLE | LiveScript could not read the live source or YouTube rejected the stream request. |
| USAGE_LIMIT_EXCEEDED | The account has no live minutes remaining for this period or top-up balance. |
| CONCURRENT_STREAM_LIMIT | The account is already using the maximum number of concurrent live streams. |