Async Jobs

For long-running video processing, use the async jobs API. Submit a job, get a job ID, and poll for progress and results.

When to Use Async Jobs

  • Videos longer than ~15 seconds
  • When you need progress updates for a UI
  • When processing from the playground (used automatically)
  • When you want webhook notifications on completion

Submit a Job

Request
POST /api/v1/jobs/video/remove-background
Content-Type: multipart/form-data
Authorization: Bearer YOUR_API_KEY

Accepts the same parameters as the sync endpoint. Returns immediately:

Response (202 Accepted)
{
"success": true,
"data": {
"jobId": "jd7abc123def456",
"status": "queued"
}
}

Poll for Status

bash
GET /api/v1/jobs/{jobId}
Authorization: Bearer YOUR_API_KEY

Job Statuses

StatusDescription
queuedJob accepted, waiting to start
submittedJob submitted to processor
processingActively processing (check progress and stage)
completedDone — result contains download URLs
failedFailed — error contains details

Processing Stages

StageProgressDescription
queued-on-railway0-10%Waiting for processor
loading-input10-25%Downloading/loading video
processing-video25-85%Removing background frame-by-frame
uploading-outputs85-100%Uploading results to storage

Completed Response

json
{
"success": true,
"data": {
"jobId": "jd7abc123def456",
"type": "video",
"status": "completed",
"progress": 100,
"stage": null,
"createdAt": 1710000000,
"startedAt": 1710000010,
"completedAt": 1710000070,
"error": null,
"result": {
"outputUrl": "https://storage-signed-url...",
"outputFormat": "webm",
"outputSize": 1597805,
"width": 768,
"height": 768,
"processingTimeMs": 12500,
"detectedBackgroundColor": { "r": 233, "g": 47, "b": 188, "hex": "#E92FBC" },
"outputs": [
{ "format": "webm", "url": "https://...", "size": 1597805 },
{ "format": "stacked-alpha", "url": "https://...", "size": 5242880 }
]
}
}
}

Polling Example (SDK)

typescript
import { Hypervideo } from '@hypervideo-dev/sdk';
const client = new Hypervideo({ apiKey: 'hc_...' });
// Submit
const { jobId } = await client.jobs.submit({
file: videoFile,
formats: ['webm', 'stacked-alpha'],
});
// Poll with progress callback
const job = await client.jobs.poll(jobId, {
onProgress: (j) => {
console.log(`${j.progress}% - ${j.stage}`);
},
});
// Download result
console.log(job.result.outputs);

Polling Example (curl)

bash
# Submit job
JOB_ID=$(curl -s -X POST https://api.hypervideo.dev/api/v1/jobs/video/remove-background \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@video.mp4" \
-F "format=webm" | jq -r '.data.jobId')
echo "Job submitted: $JOB_ID"
# Poll every 3 seconds
while true; do
RESULT=$(curl -s https://api.hypervideo.dev/api/v1/jobs/$JOB_ID \
-H "Authorization: Bearer YOUR_API_KEY")
STATUS=$(echo $RESULT | jq -r '.data.status')
PROGRESS=$(echo $RESULT | jq -r '.data.progress')
echo "Status: $STATUS ($PROGRESS%)"
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
echo $RESULT | jq '.data.result'
break
fi
sleep 3
done

Access Control

Users can only access their own jobs. The API key used to submit the job must be the same key used to poll for results.