Generate video clips from a text prompt with Qubax. Because video synthesis is asynchronous, the endpoint follows an async pattern: you submit a generation job with a POST request, poll its status, and finally download the finished artifact.
The workflow has three steps:
1. POST /v1/video/generations → returns a job ID (status: "pending")
2. GET /v1/video/generations/{id} → poll until status is "completed" or "failed"
3. GET /v1/media/artifacts/{jobId}/{index} → download the finished video bytesAll requests require an API key passed as a Bearer token in the Authorization header:
Authorization: Bearer qbx_live_...POST https://api.qubax.ai/v1/video/generations| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | ID of the video model to use (e.g. runway-gen4-5-text). |
| prompt | string | Yes | Text description of the desired video motion and scene. |
duration, aspect_ratio, or an image seed. Unsupported parameters are ignored. Model availability can be discovered via GET /v1/models.Using requests to submit the job, poll for status, and finally download the artifact:
import time
import requests
BASE = "https://api.qubax.ai/v1"
HEADERS = {"Authorization": "Bearer qbx_live_..."}
# 1. Create the generation job
resp = requests.post(
f"{BASE}/video/generations",
headers=HEADERS,
json={"model": "runway-gen4-5-text", "prompt": "ocean waves crashing on a reef at sunset"},
)
job = resp.json()
job_id = job["id"]
print("Created job:", job_id)
# 2. Poll for status until terminal
poll_url = f"{BASE}/video/generations/{job_id}"
while True:
status = requests.get(poll_url, headers=HEADERS).json()
state = status["status"]
print("status:", state)
if state in ("completed", "failed"):
break
time.sleep(10)
if state != "completed":
raise RuntimeError("Video generation failed:", status)
# 3. Download the finished artifact(s)
output_count = status.get("output_count", 1)
for i in range(output_count):
dl = requests.get(f"{BASE}/media/artifacts/{job_id}/{i}", headers=HEADERS)
with open(f"video_{job_id}_{i}.mp4", "wb") as f:
f.write(dl.content)
print("Done.")Create the job and capture the returned id:
curl https://api.qubax.ai/v1/video/generations \
-H "Authorization: Bearer *** \
-H "Content-Type: application/json" \
-d '{
"model": "runway-gen4-5-text",
"prompt": "ocean waves crashing on a reef at sunset"
}'Poll the status endpoint until the job is completed:
curl https://api.qubax.ai/v1/video/generations/{id} \
-H "Authorization: Bearer ***Once complete, download the artifact by index (typically 0):
curl https://api.qubax.ai/v1/media/artifacts/{jobId}/0 \
-H "Authorization: Bearer *** \
-o video.mp4GET https://api.qubax.ai/v1/video/generations/{id}The status field moves through the values below. Re-poll with backoff until it reaches a terminal state.
| Status | Meaning |
|---|---|
| pending | Job accepted and queued, not yet started. |
| processing | The model is actively generating frames. |
| completed | Artifacts are ready for download. |
| failed | Generation failed; see error in the status body. |
GET https://api.qubax.ai/v1/media/artifacts/{jobId}/{index}{jobId} is the job ID returned at creation, and {index} is a zero-based artifact selector. Most jobs produce a single clip at index 0; the completed status body reports the available count.
A completed status response looks like:
{
"id": "vg_abc123",
"model": "runway-gen4-5-text",
"status": "completed",
"output_count": 1,
"created_at": 1719792000,
"completed_at": 1719792120
}When status is failed, an error object is present describing the cause:
{
"id": "vg_abc123",
"status": "failed",
"error": {
"message": "Content policy violation in prompt.",
"type": "invalid_request_error"
}
}