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

ParameterTypeDescription
idstringJob ID returned when you submitted the generation (e.g. job_abc123).

Response fields

FieldTypeDescription
idstringJob ID.
statusstring"queued", "processing", "completed", or "failed".
urlstringCDN URL of the generated asset (only when completed).
modelstringModel key used for generation.
modalitystring"video", "music", or "voice".
costobjectActual cost (only when completed). Contains micro, display, currency.
estimated_costobjectEstimated cost (while queued/processing).
errorobjectError details (only when failed). Contains code and message.
metadataobjectAsset metadata (dimensions, duration, fps, etc.).
created_atstringISO 8601 timestamp of job creation.
completed_atstringISO 8601 timestamp of completion (if completed).

Status values

StatusMeaningCost charged?
queuedJob is waiting to start.No
processingJob is actively running.No
completedGeneration finished. url and cost available.Yes
failedGeneration 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

ParameterTypeDescription
statusstringFilter by status: "queued", "processing", "completed", "failed".
modalitystringFilter by modality: "video", "music", "voice".
limitintegerMax results to return (1-100). Default: 20.
cursorstringPagination 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