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-backgroundContent-Type: multipart/form-dataAuthorization: Bearer YOUR_API_KEYAccepts 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_KEYJob Statuses
| Status | Description |
|---|---|
queued | Job accepted, waiting to start |
submitted | Job submitted to processor |
processing | Actively processing (check progress and stage) |
completed | Done — result contains download URLs |
failed | Failed — error contains details |
Processing Stages
| Stage | Progress | Description |
|---|---|---|
queued-on-railway | 0-10% | Waiting for processor |
loading-input | 10-25% | Downloading/loading video |
processing-video | 25-85% | Removing background frame-by-frame |
uploading-outputs | 85-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_...' });
// Submitconst { jobId } = await client.jobs.submit({ file: videoFile, formats: ['webm', 'stacked-alpha'],});
// Poll with progress callbackconst job = await client.jobs.poll(jobId, { onProgress: (j) => { console.log(`${j.progress}% - ${j.stage}`); },});
// Download resultconsole.log(job.result.outputs);Polling Example (curl)
bash
# Submit jobJOB_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 secondswhile 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 3doneAccess 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.
