Overview
Retrieves the current status of a download job. When completed, includes a presigned S3 URL for downloading the file.
Your API key for authentication
Path Parameters
The job UUID returned from POST /jobs
Response
Job status: Pending, Processing, Completed, Failed, Warning, or Skipped
Presigned download URL (only when Completed)
Presigned URL for subtitles (if available)
Error message (when Failed, Warning, or Skipped)
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)
Current processing step: Queued, Downloading, Muxing, Uploading, Finished
Video title (only present for completed jobs fetched from database)
Video/episode description from the source platform (only present for completed jobs)
Release or upload date. Spotify: exact publish date. YouTube: upload date (midnight UTC). ISO 8601 format.
S3 folder prefix if provided at job creation
Batch UUID if this job is part of a batch (Spotify show or YouTube playlist)
Download speed in MB/s (only present for completed jobs)
Upload speed in MB/s (only present for completed jobs)
Metadata extraction duration in milliseconds (only present for completed jobs)
Download stage duration in milliseconds (only present for completed jobs)
Mux (FFmpeg) stage duration in milliseconds (only present for completed jobs)
Upload stage duration in milliseconds (only present for completed jobs)
Total pipeline duration from pop to completion in milliseconds (only present for completed jobs)
YouTube API pre-check duration in milliseconds (only present when pre-check was performed)
Time spent waiting for IO semaphore in milliseconds (only present for completed jobs)
Time spent waiting for CPU semaphore in milliseconds (only present for completed jobs)
Time spent waiting for upload semaphore in milliseconds (only present for completed jobs)
Subtitle download duration in milliseconds (only present for completed jobs with subtitles)
File move duration in milliseconds (only present for completed jobs)
File size in bytes (only present for completed jobs)
Video codec of the source stream (e.g., "avc1", "vp9", "av01"). Only present for completed jobs.
Audio codec of the source stream (e.g., "mp4a", "opus"). Only present for completed jobs.
Download strategy used: native, ytdlp, cascade. Only present for completed jobs.
Total download attempts across all strategies (only present for completed jobs)
Number of download retries attempted (only present for completed jobs)
Number of upload retries attempted (only present for completed jobs)
Time spent waiting in queue in milliseconds (only present for completed jobs)
Quality requested by the user (only present for completed jobs)
Actual quality of the downloaded video (only present for completed jobs)
Webhook delivery status (only present when webhook_url was set)
Creation timestamp in milliseconds since epoch
Completion timestamp in milliseconds since epoch (only present for completed jobs)
Examples
Request
Pending
Processing
Completed
Failed
Skipped
curl -X GET "https://api.tornadoapi.io/jobs/550e8400-e29b-41d4-a716-446655440000" \
-H "x-api-key: sk_your_api_key"
Status Values
Status Description 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
Step Description 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" ,
"description" : "The official video for Never Gonna Give You Up..." ,
"release_date" : "2009-10-25T00:00:00Z" ,
"download_speed_mbps" : 45.2 ,
"upload_speed_mbps" : 120.5 ,
"download_duration_ms" : 3200 ,
"mux_duration_ms" : 1500 ,
"upload_duration_ms" : 2100 ,
"total_duration_ms" : 8050 ,
"file_size" : 52428800 ,
"native_video_codec" : "avc1" ,
"native_audio_codec" : "mp4a" ,
"download_strategy" : "native" ,
"download_retries" : 1 ,
"upload_retries" : 0 ,
"queue_wait_ms" : 450 ,
"requested_quality" : "best" ,
"actual_quality" : "1080p" ,
"created_at" : 1705507200000 ,
"finished_at" : 1705507260000
}
Error Responses
The presigned s3_url and subtitle_url are valid for 24 hours. Download the files before they expire.
Performance and metadata fields (title, description, release_date, folder, batch_id, download_speed_mbps, upload_speed_mbps, extract_duration_ms, download_duration_ms, mux_duration_ms, upload_duration_ms, total_duration_ms, precheck_duration_ms, io_wait_ms, cpu_wait_ms, upload_wait_ms, subtitle_duration_ms, file_move_ms, file_size, native_video_codec, native_audio_codec, download_strategy, cascade_total_attempts, download_retries, upload_retries, queue_wait_ms, requested_quality, actual_quality, webhook_status, 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, error_type, step, created_at). Fields with no value are omitted from the response.
Completed jobs also echo back the original request parameters (format, video_codec, audio_codec, audio_bitrate, video_quality, filename, audio_only, download_subtitles, download_thumbnail, quality_preset, max_resolution, clip_start, clip_end, live_recording, live_from_start, max_duration, wait_for_video, enable_progress_webhook). These are omitted when null.