---
title: Get download status | Vid Kraken API
description: Poll the status of a previously-submitted download job.
url: https://vidkraken.com/docs/endpoint/get-download-status
updated: '2026-10-24'
---

# Get download status

For AI agents: docs index at https://vidkraken.com/docs/llms.txt; any page as Markdown by adding .md to its URL.

`GET https://vidkraken.com/api/v2/download/{jobId}`

Poll the status of a previously-submitted download job. Once `status`
is `COMPLETED`, the response carries a `downloadUrl` you can fetch
the file from. If `status` is `FAILED`, an `errorCode` identifies
why.

**Cost:** Free — polling is never charged.

```bash
curl -X GET "https://vidkraken.com/api/v2/download/69cfc45e8a3b4d2f9c1e0a7b" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Authorization

Bearer token. API key issued from the dashboard, sent as `Authorization: Bearer YOUR_API_KEY`. Get a key at https://vidkraken.com/login.

## Parameters

- `jobId` (path, string, required)

  The `jobId` returned from `POST /download`.

  Example: `69cfc45e8a3b4d2f9c1e0a7b`.

## Responses

### 200

Current job status.

One of:

- `DownloadJobPending`
- `DownloadJobCompleted`
- `DownloadJobFailed`

Job still running:

```json
{
  "jobId": "69cfc45e8a3b4d2f9c1e0a7b",
  "status": "IN_PROGRESS",
  "title": "Rick Astley - Never Gonna Give You Up",
  "duration": 213,
  "url": "https://youtu.be/dQw4w9WgXcQ",
  "format": "1080",
  "language": null,
  "createdAt": "2026-09-23T20:10:00Z",
  "startedAt": "2026-09-23T20:10:04Z",
  "completedAt": null,
  "progress": {
    "stage": "downloading",
    "percent": 41,
    "bytesDownloaded": 43500000,
    "totalBytes": 102300000,
    "totalBytesIsEstimate": false,
    "updatedAt": "2026-09-23T20:10:19Z"
  }
}
```

Job completed — file ready:

```json
{
  "jobId": "69cfc45e8a3b4d2f9c1e0a7b",
  "status": "COMPLETED",
  "url": "https://youtu.be/dQw4w9WgXcQ",
  "format": "1080",
  "actualFormat": "1080",
  "language": null,
  "downloadUrl": "https://proxy.vidkraken.com/media/69cfc45e8a3b4d2f9c1e0a7b.mp4",
  "title": "Rick Astley - Never Gonna Give You Up",
  "duration": 213,
  "fileSize": 32240544
}
```

Job failed with a known error code:

```json
{
  "jobId": "69cfc45e8a3b4d2f9c1e0a7b",
  "status": "FAILED",
  "errorCode": "AGE_RESTRICTED",
  "title": "Some Restricted Video",
  "duration": 412,
  "url": "https://youtu.be/example",
  "format": "1080"
}
```

### 401

Missing or invalid API key.

Body: `ApiError`.

missing:

```json
{
  "error": "Missing API key. Provide it as 'Bearer YOUR_API_KEY'",
  "code": "UNAUTHORIZED"
}
```

invalid:

```json
{
  "error": "Invalid API key",
  "code": "UNAUTHORIZED"
}
```

### 404

Job not found, expired, or belongs to another user.

Body: `ApiError`.

```json
{
  "error": "Download job not found",
  "code": "NOT_FOUND"
}
```

### 500

Unexpected server error.

Body: `ApiError`.

```json
{
  "error": "Failed to enqueue download job",
  "code": "INTERNAL_ERROR"
}
```

## Schemas

### `DownloadJobPending`

- `jobId` (string, required)

- `status` (string, required)

  One of: `IN_QUEUE`, `IN_PROGRESS`.

- `title` (string, required)

- `duration` (integer, required)

  Full video duration in seconds.

- `url` (string, required)

  The original YouTube URL submitted.

- `format` (`MediaFormat`, required)

- `language` (string or null)

  Audio language requested in the original POST, or `null` if none was specified.

- `createdAt` (string (date-time))

  When the job was submitted (ISO 8601).

- `startedAt` (string or null (date-time))

  When processing started, or `null` if still queued.

- `completedAt` (string or null (date-time))

  When the job reached a terminal state, or `null`.

- `progress` (`DownloadProgress`)

### `DownloadJobCompleted`

- `jobId` (string, required)

- `status` (string, required)

  One of: `COMPLETED`.

- `url` (string, required)

  The original YouTube URL submitted.

- `format` (`MediaFormat`, required)

  The format requested in the original POST.

- `actualFormat` (`MediaFormat`, required)

  Format actually delivered. May differ from the requested format if the video isn't available in that quality.

- `language` (string or null)

  Audio language requested in the original POST, or `null` if none was specified. The actual language used may differ if a fallback was applied.

- `downloadUrl` (string (uri), required)

  CDN URL to download the produced file from.

- `title` (string, required)

- `duration` (integer, required)

  Full video duration in seconds.

- `fileSize` (integer, required)

  Size of the produced file in bytes.

- `createdAt` (string (date-time))

  When the job was submitted (ISO 8601).

- `startedAt` (string or null (date-time))

  When processing started, or `null` if still queued.

- `completedAt` (string or null (date-time))

  When the job reached a terminal state, or `null`.

### `DownloadJobFailed`

- `jobId` (string, required)

- `status` (string, required)

  One of: `FAILED`.

- `errorCode` (`DownloadErrorCode`)

- `title` (string, required)

- `duration` (integer, required)

- `url` (string, required)

- `format` (`MediaFormat`, required)

- `language` (string or null)

  Audio language requested in the original POST, or `null` if none was specified.

- `createdAt` (string (date-time))

  When the job was submitted (ISO 8601).

- `startedAt` (string or null (date-time))

  When processing started, or `null` if still queued.

- `completedAt` (string or null (date-time))

  When the job reached a terminal state, or `null`.

### `ApiError`

- `error` (string, required)

  Human-readable error message.

- `code` (string, required)

  Machine-readable error code; branch on this rather than on
  `error`. New codes may be added, so treat an unknown one by
  its HTTP status. See the table under Errors in the API
  description for what each one means.

  One of: `INVALID_REQUEST`, `UNAUTHORIZED`, `LIMIT_REACHED`, `NOT_FOUND`, `VIDEO_NOT_FOUND`, `IDEMPOTENCY_CONFLICT`, `IDEMPOTENCY_KEY_REUSED`, `TOO_MANY_PENDING`, `INTERNAL_ERROR`, `UNAVAILABLE`.

- `details` (string)

  Optional extra context — e.g. yt-dlp's error message on `500`s.

### `MediaFormat`

Target media format. Numeric values are vertical resolutions in
pixels, delivered as MP4.

`audio` delivers the best audio stream YouTube serves, in whatever
container YouTube gives it — usually M4A (AAC) or WebM (Opus), at
roughly 130–160 kbps. Nothing is re-encoded, so it is the fastest
option and the highest quality available. Use this unless your
pipeline needs one specific container. Note that YouTube does not
serve higher audio bitrates for regular videos, so no option here
produces better audio than this one.

`audio-aac` prefers YouTube's AAC stream (M4A, ~128 kbps) over Opus —
the most widely compatible audio codec, and useful when a pipeline was
calibrated on AAC. Nothing is re-encoded. If YouTube offers no AAC
stream for a video, the best available audio is delivered instead and
`actualFormat` reports `audio` rather than `audio-aac`, so the
substitution is visible.

`audio-mp3` always delivers an MP3, encoded at 320 kbps CBR — the
highest rate the MP3 format defines — using LAME's best-quality
analysis. The source's sample rate and channel layout are preserved
rather than forced: 48 kHz audio stays 48 kHz with no resampling, and
a mono source stays mono.

Type: string.

One of: `1080`, `720`, `480`, `360`, `audio`, `audio-aac`, `audio-mp3`.

### `DownloadProgress`

Live progress of a running job. Present on `IN_QUEUE` and `IN_PROGRESS`
responses once there is something to report; absent otherwise. Poll as
often as you like — polling is never charged.

- `stage` (string, required)

  Where the job is. The same stages for every job, trimmed or not.
  A stage may repeat (for example `extracting` after `downloading`)
  when the job switches route mid-way; `percent` never moves
  backwards.

  One of: `queued`, `starting`, `extracting`, `downloading`, `processing`, `uploading`.

- `percent` (integer, required)

  Overall progress. Only ever increases; reaches 100 when `status` becomes `COMPLETED`.

- `bytesDownloaded` (integer, required)

  Bytes received so far in the current transfer.

- `totalBytes` (integer or null, required)

  Total bytes of the transfer. An estimate from format and duration until the real size is known.

- `totalBytesIsEstimate` (boolean, required)

  `true` while `totalBytes` is an estimate.

- `etaSeconds` (integer or null, required)

  Seconds until the job is expected to complete. Deliberately
  pessimistic: transfer rates are discounted and the stages still to
  come are padded, so it usually runs down faster than the clock. It
  can rise when the job switches route mid-way. `null` when there is
  nothing to base it on.

- `queuePosition` (integer or null)

  Only while `stage` is `queued`: place in the queue, `1` = next to
  start. `null` if it could not be counted at that moment.

- `updatedAt` (string (date-time), required)

  When the worker last reported (ISO 8601).

### `DownloadErrorCode`

Machine-readable failure reason. Except for `NETWORK_ERROR`, every
value below describes the video or our policy, not a fault on our
side — retrying will return the same result, so treat them as final.

Other values may appear for transient infra failures — retry after a
short backoff before treating them as fatal.

- `AGE_RESTRICTED` — sign-in required by YouTube for this video
- `MEMBERS_ONLY` — restricted to channel members
- `PAYMENT_REQUIRED` — purchase or rental required
- `PRIVATE_VIDEO` — the video is private
- `VIDEO_PREMIERE` — a scheduled premiere that has not aired yet; retry after the premiere starts
- `GEO_RESTRICTED` — not available in the server region
- `VIDEO_PROCESSING` — YouTube is still processing the video, usually a fresh upload or a live stream that ended recently; retry later
- `VIDEO_UNAVAILABLE` — unavailable for an unspecified reason
- `DRM_PROTECTED` — DRM protected
- `VIDEO_NOT_FOUND` — no such video, or it has been deleted
- `FORMAT_UNAVAILABLE` — the requested format/quality is not offered
- `LIVE_STREAM_IN_PROGRESS` — still live; retry once it has ended
- `COPYRIGHTED_MUSIC` — copyrighted music, not downloadable here
- `NO_DOWNLOAD_OPT_OUT` — the creator opted out via `#nodownload`
- `FILE_TOO_LARGE` — the file in this format is larger than we can deliver; try a lower-quality format or a shorter clip
- `NETWORK_ERROR` — transient network failure on our side; retry after a short backoff

Type: string.

One of: `AGE_RESTRICTED`, `MEMBERS_ONLY`, `PAYMENT_REQUIRED`, `PRIVATE_VIDEO`, `VIDEO_PREMIERE`, `GEO_RESTRICTED`, `VIDEO_PROCESSING`, `VIDEO_UNAVAILABLE`, `DRM_PROTECTED`, `VIDEO_NOT_FOUND`, `FORMAT_UNAVAILABLE`, `LIVE_STREAM_IN_PROGRESS`, `COPYRIGHTED_MUSIC`, `NO_DOWNLOAD_OPT_OUT`, `FILE_TOO_LARGE`, `NETWORK_ERROR`.

Full API reference, including the download.finished webhook: https://vidkraken.com/docs.md · OpenAPI: https://vidkraken.com/openapi.json
