> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bestvideotranscriptapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Jobs and polling

> What to do when a transcript takes longer than 25 seconds.

`GET /v1/transcript` waits up to **25 seconds**. Most caption requests finish well inside that. If the transcript isn't ready, usually because a long video is being transcribed with AI, you get a job instead:

```http theme={null}
HTTP/1.1 202 Accepted
Retry-After: 30

{ "jobId": "run_cmh2x8k0a00fz2..." }
```

The work keeps running. Poll `GET /v1/transcript/{jobId}` about every 30 seconds until `status` is `completed` or `failed`.

```mermaid theme={null}
sequenceDiagram
  participant You
  participant API
  You->>API: GET /v1/transcript?url=...
  Note over API: Waits up to 25 s
  API-->>You: 202 + jobId
  loop Every 30 s
    You->>API: GET /v1/transcript/{jobId}
    API-->>You: 200, status active
  end
  You->>API: GET /v1/transcript/{jobId}
  API-->>You: 200, status completed + transcript
```

```bash theme={null}
curl https://app.bestvideotranscriptapi.com/v1/transcript/run_cmh2x8k0a00fz2... \
  -H "x-api-key: $VIDEO_TRANSCRIPT_API_KEY"
```

## Job status

A poll for your own job always returns `200`, even when the job failed, because the poll itself worked. Check `status`, not the HTTP code.

| `status` | Body |
| - | - |
| `queued` | Waiting to start. |
| `active` | Being transcribed. |
| `completed` | The transcript, in the same shape as `GET /v1/transcript`. |
| `failed` | An `error` object with `code` and `message`. See [Errors](https://docs.bestvideotranscriptapi.com/errors.md). |

Pass `text=true` on the poll to get the finished transcript as one string.

## Full example

```javascript theme={null}
// Ask for the transcript, then poll until it's done
async function transcript(url) {
   const headers = { "x-api-key": process.env.VIDEO_TRANSCRIPT_API_KEY }
   const base = "https://app.bestvideotranscriptapi.com/v1/transcript"
   let res = await fetch(`${base}?${new URLSearchParams({ url })}`, { headers })
   let body = await res.json()
   if (res.status !== 202) return body

   const { jobId } = body
   while (true) {
      await new Promise((resolve) => setTimeout(resolve, 30_000))
      body = await (await fetch(`${base}/${jobId}`, { headers })).json()
      if (body.status === "completed" || body.status === "failed") return body
   }
}
```

## Retries are safe

Send the same request again (same `url`, `lang` and `mode`) within an hour and you get the same job back. You're charged once, so retrying after a timeout or a dropped connection is safe.

## Logs

Every request from the API, MCP or the Playground shows up on the [Logs](https://app.bestvideotranscriptapi.com/dashboard/logs) page for 30 days, with its status and the AI minutes it used.

![Browsing recent requests on the Logs page](https://mintcdn.com/tatsat-bodhaa-opc-private-limited/YVscscAdRf-4dZpR/images/logs.gif?s=affc7117e73f0cee73ebd1f0cb47b82f)

The Logs page


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.