Jobs API
Create and manage long-running workflow jobs. Jobs are used for complex operations like video generation that take several minutes to complete.
Endpoints
POST
/api/v1/jobsCreate a new job
GET
/api/v1/jobsList your jobs
GET
/api/v1/jobs/{id}Get job status
DELETE
/api/v1/jobs/{id}Cancel a job
Create a Job
POST
/api/v1/jobsRequest Body
| Name | Type | Description |
|---|---|---|
workflowrequired | string | Workflow slug (e.g., 'house-timelapse', 'renovation-timelapse') |
input | object | Workflow-specific input parameters |
webhookUrl | string | URL to receive completion notification |
Example Request
"text">-purple-600">curl "text-blue-600">-X POST https://vydra.app/api/v1/jobs \
"text-blue-600">-H "Authorization: Bearer YOUR_API_KEY" \
"text-blue-600">-H "Content">-Type: application/json" \
"text-blue-600">-d '{
"workflow": "house">-timelapse",
"input": {
"theme": "Cliffside Ocean Mansion"
},
"webhookUrl": "https://yourapp.com/webhook/vydra"
}'Response (201 Created)json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"workflow": "house-timelapse",
"creditsCharged": 150,
"createdAt": "2026-01-26T12:00:00.000Z",
"_links": {
"self": "https://vydra.app/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000",
"status": "https://vydra.app/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000"
}
}List Jobs
GET
/api/v1/jobsQuery Parameters
| Name | Type | Description |
|---|---|---|
limit | numberDefault: 20 | Max results (1-100) |
offset | numberDefault: 0 | Pagination offset |
status | string | Filter by status: pending, running, completed, failed |
Examplebash
"text">-purple-600">curl "https://vydra.app/api/v1/jobs?limit=10&status=completed" \
"text-blue-600">-H "Authorization: Bearer YOUR_API_KEY"Responsejson
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"progress": 100,
"workflowSlug": "house-timelapse",
"statusMessage": "Video generated successfully",
"creditsCharged": 150,
"createdAt": "2026-01-26T12:00:00.000Z",
"completedAt": "2026-01-26T12:15:00.000Z",
"output": {
"videoUrl": "https://pub-xxx.r2.dev/videos/output.mp4"
}
}
],
"pagination": {
"limit": 10,
"offset": 0,
"count": 1
}
}Get Job Status
GET
/api/v1/jobs/{id}Examplebash
"text">-purple-600">curl https://vydra.app/api/v1/jobs/550e8400"text-blue-600">-e29b-41d4"text-blue-600">-a716-446655440000 \
"text-blue-600">-H "Authorization: Bearer YOUR_API_KEY"Response States
Pending
{
"id": "...",
"status": "pending",
"progress": 0,
"statusMessage": "Waiting to start..."
}Running
{
"id": "...",
"status": "running",
"progress": 45,
"statusMessage": "Generating video 2 of 3..."
}Completed
{
"id": "...",
"status": "completed",
"progress": 100,
"output": {
"videoUrl": "https://pub-xxx.r2.dev/videos/output.mp4",
"thumbnailUrl": "https://pub-xxx.r2.dev/videos/thumbnail.jpg"
}
}Failed
{
"id": "...",
"status": "failed",
"error": {
"message": "Processing error",
"code": "PROCESSING_ERROR"
},
"creditsRefunded": 150,
"refundStatus": "completed"
}Cancel a Job
DELETE
/api/v1/jobs/{id}Examplebash
"text">-purple-600">curl "text-blue-600">-X DELETE https://vydra.app/api/v1/jobs/550e8400"text-blue-600">-e29b-41d4"text-blue-600">-a716-446655440000 \
"text-blue-600">-H "Authorization: Bearer YOUR_API_KEY"Responsejson
{
"success": true,
"message": "Job cancelled",
"refund": {
"applied": true,
"creditsRefunded": 150
}
}Auto-Refund on Cancel
When you cancel a job, any charged credits are automatically refunded.
Webhooks
Instead of polling for status, provide a webhookUrl to receive notifications when jobs complete.
Webhook Payload (Success)
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"workflow": "house-timelapse",
"output": {
"videoUrl": "https://pub-xxx.r2.dev/videos/output.mp4"
},
"completedAt": "2026-01-26T12:15:00.000Z"
}Webhook Payload (Failure)
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"workflow": "renovation-timelapse",
"error": {
"message": "Processing failed",
"code": "PROCESSING_ERROR"
},
"refund": {
"applied": true,
"creditsRefunded": 50
},
"completedAt": "2026-01-26T12:15:00.000Z"
}Job Statuses
| Status | Description | Final? |
|---|---|---|
pending | Job created, waiting to start | No |
running | Job is actively processing | No |
completed | Job finished successfully | Yes |
failed | Job encountered an error | Yes |
cancelled | Job was cancelled by user | Yes |
Polling Example
If you can't use webhooks, poll for status:
Polling Implementationjavascript
"text-purple-600">async "text-purple-600">function waitForJob(jobId, apiKey, maxWaitMs = 30 * 60 * 1000) {
"text-purple-600">const startTime = Date.now();
"text-purple-600">const pollInterval = 5000; // 5 seconds
while (Date.now() - startTime < maxWaitMs) {
"text-purple-600">const response = "text-purple-600">await fetch(`https://vydra.app/api/v1/jobs/${jobId}`, {
headers: { "text-green-600">'Authorization': `Bearer ${apiKey}` }
});
"text-purple-600">const job = "text-purple-600">await response.json();
console.log(`Status: ${job.status}, Progress: ${job.progress}%`);
"text-purple-600">if (job.status === "text-green-600">'completed') {
"text-purple-600">return job.output;
}
"text-purple-600">if (job.status === "text-green-600">'failed') {
throw "text-purple-600">new Error(job.error?.message || "text-green-600">'Job failed');
}
// Wait before next poll
"text-purple-600">await "text-purple-600">new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw "text-purple-600">new Error("text-green-600">'Job timed out');
}
// Usage
"text-purple-600">const output = "text-purple-600">await waitForJob("text-green-600">'job-id', "text-green-600">'YOUR_API_KEY');
console.log("text-green-600">'Video URL:', output.videoUrl);Rate Limits
Polling counts against your rate limits. Use webhooks when possible, or poll no more than once every 5 seconds.