Skip to main content
GET
/
jobs
/
{id}
Get Job Status
curl --request GET \
  --url https://api.tornadoapi.io/jobs/{id} \
  --header 'x-api-key: <x-api-key>'
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
  "status": "Completed",
  "s3_url": "https://cdn.example.com/videos/video.mp4?X-Amz-Algorithm=...",
  "subtitle_url": null,
  "error": null,
  "step": "Finished",
  "title": "Rick Astley - Never Gonna Give You Up",
  "download_speed_mbps": 45.2,
  "download_duration_ms": 3200,
  "mux_duration_ms": 1500,
  "upload_duration_ms": 2100,
  "file_size": 52428800,
  "download_retries": 1,
  "upload_retries": 0,
  "queue_wait_ms": 450,
  "requested_quality": "best",
  "actual_quality": "1080p",
  "created_at": 1705507200000,
  "finished_at": 1705507260000
}

Overview

Retrieves the current status of a download job. When completed, includes a presigned S3 URL for downloading the file.

Header Parameters

x-api-key
string
required
Your API key for authentication

Path Parameters

id
string
required
The job UUID returned from POST /jobs

Response

id
string
Job UUID
url
string
Original source URL
status
string
Job status: Pending, Processing, Completed, Failed, Warning, or Skipped
s3_url
string
Presigned download URL (only when Completed)
subtitle_url
string
Presigned URL for subtitles (if available)
error
string
Error message (when Failed, Warning, or Skipped)
error_type
string
Error classification (when Failed, Warning, or Skipped): error for technical failures (rate limits, bot detection, connection issues), warning for content issues (private video, members-only, geo-blocked, audio-only Spotify episodes)
step
string
Current processing step: Queued, Downloading, Muxing, Uploading, Finished
title
string
Video title (only present for completed jobs fetched from database)
download_speed_mbps
number
Download speed in MB/s (only present for completed jobs)
download_duration_ms
integer
Download stage duration in milliseconds (only present for completed jobs)
mux_duration_ms
integer
Mux (FFmpeg) stage duration in milliseconds (only present for completed jobs)
upload_duration_ms
integer
Upload stage duration in milliseconds (only present for completed jobs)
file_size
integer
File size in bytes (only present for completed jobs)
download_retries
integer
Number of download retries attempted (only present for completed jobs)
upload_retries
integer
Number of upload retries attempted (only present for completed jobs)
queue_wait_ms
integer
Time spent waiting in queue in milliseconds (only present for completed jobs)
requested_quality
string
Quality requested by the user (only present for completed jobs)
actual_quality
string
Actual quality of the downloaded video (only present for completed jobs)
webhook_status
string
Webhook delivery status (only present when webhook_url was set)
created_at
integer
Creation timestamp in milliseconds since epoch
finished_at
integer
Completion timestamp in milliseconds since epoch (only present for completed jobs)

Examples

curl -X GET "https://api.tornadoapi.io/jobs/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-api-key: sk_your_api_key"

Status Values

StatusDescription
PendingJob is in queue, waiting to be processed
ProcessingJob is actively being downloaded/processed
CompletedJob finished successfully
FailedJob encountered a technical error
WarningJob failed due to a content issue (private video, members-only, geo-blocked, unavailable)
SkippedJob was skipped because the content cannot be processed (e.g. audio-only Spotify episodes with Widevine DRM)

Processing Steps

StepDescription
QueuedWaiting in queue
DownloadingDownloading video/audio streams
MuxingCombining streams with FFmpeg
UploadingUploading to S3
FinishedComplete

Polling Example

import requests
import time

def wait_for_job(job_id, api_key, timeout=600):
    start = time.time()

    while time.time() - start < timeout:
        response = requests.get(
            f"https://api.tornadoapi.io/jobs/{job_id}",
            headers={"x-api-key": api_key}
        )
        data = response.json()

        print(f"Status: {data['status']} - {data.get('step', 'N/A')}")

        if data["status"] == "Completed":
            return data["s3_url"]
        elif data["status"] == "Failed":
            raise Exception(f"Job failed: {data['error']}")
        elif data["status"] == "Skipped":
            print(f"Job skipped: {data['error']}")
            return None

        time.sleep(3)

    raise Exception("Timeout waiting for job")

Success Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
  "status": "Completed",
  "s3_url": "https://cdn.example.com/videos/video.mp4?X-Amz-Algorithm=...",
  "subtitle_url": null,
  "error": null,
  "step": "Finished",
  "title": "Rick Astley - Never Gonna Give You Up",
  "download_speed_mbps": 45.2,
  "download_duration_ms": 3200,
  "mux_duration_ms": 1500,
  "upload_duration_ms": 2100,
  "file_size": 52428800,
  "download_retries": 1,
  "upload_retries": 0,
  "queue_wait_ms": 450,
  "requested_quality": "best",
  "actual_quality": "1080p",
  "created_at": 1705507200000,
  "finished_at": 1705507260000
}

Error Responses

null
The presigned s3_url is valid for 24 hours. Download the file before it expires.
Performance fields (title, download_speed_mbps, download_duration_ms, mux_duration_ms, upload_duration_ms, file_size, download_retries, upload_retries, queue_wait_ms, requested_quality, actual_quality, finished_at) are only present for completed/failed jobs that have been persisted to the database. Active jobs (Pending/Processing) return only the base fields (id, url, status, s3_url, subtitle_url, error, step, created_at). Fields with no value are omitted from the response.