Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.transcribetube.com/llms.txt

Use this file to discover all available pages before exploring further.

POST /api/transcribeVideo returns immediately with a projectId — the actual transcription happens asynchronously in the background and typically takes between a few seconds and several minutes depending on video length and queue load. There are two ways to find out when a transcription is ready: webhook (push) or polling (pull). You can use either, or both.

Project States

Every project moves through a small set of states. The current value is returned in the state field of GET /api/detail/{id}.
StateMeaningAction
uploadThe video is being downloaded from YouTube and uploaded to our storage.Wait.
transcriptionThe audio is being transcribed by our speech engine.Wait.
doneTranscription finished, full text and transcript JSON available.Read the result.
errorSomething failed in the pipeline.Retry (re-submit), or contact support if it persists.
A typical run looks like: upload → transcription → done. Most videos under 10 minutes complete in 30–90 seconds total. Provide a webhookUrl when you call POST /api/transcribeVideo:
{
  "youtubeVideoId": "dQw4w9WgXcQ",
  "language": "en",
  "webhookUrl": "https://yourapp.com/hooks/transcribetube"
}
When the project reaches done, we POST the full payload to your URL. See Webhooks for the payload shape, headers, and the (lack of) retry policy.

Pattern 2: Polling

If you don’t have a public webhook endpoint, poll GET /api/detail/{id} periodically until the state is done.
async function waitForTranscription(projectId, apiKey, { intervalMs = 5000, maxMs = 600000 } = {}) {
  const deadline = Date.now() + maxMs;
  while (Date.now() < deadline) {
    const res = await fetch(`https://api.transcribetube.com/api/detail/${projectId}`, {
      headers: { "api-key": apiKey },
    });
    const project = await res.json();
    if (project.state === "done") return project;
    if (project.state === "error") throw new Error(`Project ${projectId} failed`);
    await new Promise((r) => setTimeout(r, intervalMs));
  }
  throw new Error(`Timed out waiting for project ${projectId}`);
}
Recommended cadence:
  • Poll every 5–10 seconds for the first 2 minutes (short videos finish fast).
  • Then back off to 30–60 seconds for the next 10 minutes.
  • Give up after ~10 minutes and report a failure — the project will likely be in error state by then.
Polling more frequently than once every 3 seconds wastes both your quota and our rate limits without making the job complete any sooner.

Pattern 3: Both (most robust)

The webhook is single-attempt and not retried (see Webhooks). To make sure you never miss a result:
  1. Submit with a webhookUrl.
  2. Have your webhook handler mark the project as “received” in your own database.
  3. Run a background job every few minutes that lists pending projects via GET /api/list and reconciles any that didn’t get a webhook by calling GET /api/detail/{id}.

Response Shape by State

Note that GET /api/detail/{id} returns different fields depending on state:
{
  "id": "f3c1e7a0-2b48-4a91-8a30-9b1c2d3e4f50",
  "name": "Rick Astley - Never Gonna Give You Up",
  "youtubeId": "dQw4w9WgXcQ",
  "language": "en",
  "text": "We're no strangers to love\n\nYou know the rules and so do I\n\n..."
}
Detect “ready” by checking state === "done" or by the presence of the text field.