Documentation Navigation
Getting Started
API Reference
Resources
Jobs API
Poll async generation jobs, list job history, cancel pending jobs, and handle webhook callbacks.
Async generations. Video and music generation are always async. Long-form voice may also be async. Use this API to poll for results, or provide a
webhook_url when submitting the job. GET /v1/jobs/:id
Check the status of an async generation job. Poll this endpoint until status is "completed" or "failed".
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Job ID returned when you submitted the generation (e.g. job_abc123). |
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Job ID. |
status | string | "queued", "processing", "completed", or "failed". |
url | string | CDN URL of the generated asset (only when completed). |
model | string | Model key used for generation. |
modality | string | "video", "music", or "voice". |
cost | object | Actual cost (only when completed). Contains micro, display, currency. |
estimated_cost | object | Estimated cost (while queued/processing). |
error | object | Error details (only when failed). Contains code and message. |
metadata | object | Asset metadata (dimensions, duration, fps, etc.). |
created_at | string | ISO 8601 timestamp of job creation. |
completed_at | string | ISO 8601 timestamp of completion (if completed). |
Status values
| Status | Meaning | Cost charged? |
|---|---|---|
queued | Job is waiting to start. | No |
processing | Job is actively running. | No |
completed | Generation finished. url and cost available. | Yes |
failed | Generation failed. error available. | No |
Code examples
curl
curl https://api.fairstack.ai/v1/jobs/job_abc123 \
-H "Authorization: Bearer $FAIRSTACK_API_KEY" Python (polling)
from fairstack import FairStack
client = FairStack(api_key="fs_live_YOUR_KEY")
# Submit a video generation job
job = client.generate.video(
model="wan-2-1-t2v",
prompt="A cat walking on a beach at sunset"
)
# Option 1: Block until complete
result = job.wait()
print(result.url)
# Option 2: Poll manually
import time
while True:
status = client.jobs.get(job.id)
if status.status == "completed":
print(status.url)
break
elif status.status == "failed":
print(status.error)
break
time.sleep(2) Node.js (polling)
import { FairStack } from "fairstack";
const client = new FairStack({ apiKey: "fs_live_YOUR_KEY" });
// Submit a video generation job
const job = await client.generate.video({
model: "wan-2-1-t2v",
prompt: "A cat walking on a beach at sunset",
});
// Option 1: Block until complete
const result = await job.wait();
console.log(result.url);
// Option 2: Poll manually
const poll = async (jobId: string) => {
while (true) {
const status = await client.jobs.get(jobId);
if (status.status === "completed") return status;
if (status.status === "failed") throw new Error(status.error.message);
await new Promise((r) => setTimeout(r, 2000));
}
}; Queued response
{
"id": "job_abc123",
"status": "queued",
"estimated_cost": {
"micro": 48000,
"display": "$0.048"
},
"model": "wan-2-1-t2v",
"modality": "video",
"created_at": "2026-03-10T14:30:00Z"
} Completed response
{
"id": "job_abc123",
"status": "completed",
"url": "https://media.fairstack.ai/video/.../output.mp4",
"model": "wan-2-1-t2v",
"modality": "video",
"cost": {
"micro": 48000,
"display": "$0.048",
"currency": "USD"
},
"metadata": {
"width": 1280,
"height": 720,
"duration": 5,
"fps": 24
},
"created_at": "2026-03-10T14:30:00Z",
"completed_at": "2026-03-10T14:30:42Z"
} Failed response
{
"id": "job_abc123",
"status": "failed",
"error": {
"code": "generation_failed",
"message": "Content moderation filter triggered"
},
"model": "wan-2-1-t2v",
"modality": "video",
"cost": {
"micro": 0,
"display": "$0.00"
},
"created_at": "2026-03-10T14:30:00Z",
"failed_at": "2026-03-10T14:30:15Z"
} GET /v1/jobs
List your recent generation jobs with optional filters.
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: "queued", "processing", "completed", "failed". |
modality | string | Filter by modality: "video", "music", "voice". |
limit | integer | Max results to return (1-100). Default: 20. |
cursor | string | Pagination cursor from a previous response. |
curl "https://api.fairstack.ai/v1/jobs?status=completed&limit=10" \
-H "Authorization: Bearer $FAIRSTACK_API_KEY" {
"jobs": [
{ "id": "job_abc123", "status": "completed", "model": "wan-2-1-t2v", "modality": "video", "created_at": "..." },
{ "id": "job_def456", "status": "completed", "model": "suno-v4-5", "modality": "music", "created_at": "..." }
],
"has_more": true,
"cursor": "cursor_xyz"
} POST /v1/jobs/:id/cancel
Cancel a queued or processing job. No charge for cancelled jobs.
curl -X POST https://api.fairstack.ai/v1/jobs/job_abc123/cancel \
-H "Authorization: Bearer $FAIRSTACK_API_KEY" Returns the job object with status: "cancelled". Jobs that have already completed or failed cannot be cancelled.
Webhooks
Instead of polling, provide a webhook_url when submitting a generation. FairStack will POST the result to your URL when the job completes or fails.
// POST to your webhook_url when the job completes:
{
"event": "job.completed",
"job": {
"id": "job_abc123",
"status": "completed",
"url": "https://media.fairstack.ai/video/.../output.mp4",
"cost": { "micro": 48000, "display": "$0.048" }
}
} Webhook requests include an X-FairStack-Signature header for verification. Respond with a 2xx status. Failed deliveries are retried up to 3 times with exponential backoff.
Polling best practices
- Start polling 2-3 seconds after submission.
- Use a 2-5 second interval between polls.
- Set a timeout (e.g. 5 minutes) to avoid infinite polling.
- For production: prefer webhooks over polling to reduce API calls.
- The SDK
.wait()method handles polling with automatic backoff.
Next steps
- Video API -- submit video generation jobs
- Music API -- submit music generation jobs
- Error Handling -- retries and idempotency