Videos
Generates a video from a prompt in the OpenAI Videos format. Videos take minutes, so they run as tasks: create the task, poll it, and download the file when it completes. Paid video models from providers are priced per second of video; see freetheai.org/models.
https://api.freetheai.org/v1/videosCreate the task
curl https://api.freetheai.org/v1/videos \
-H "Authorization: Bearer $FTAI_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "MODEL_ID", "prompt": "Waves rolling onto a beach at sunset", "seconds": 8}'import os, time
import requests
base = "https://api.freetheai.org/v1"
headers = {"Authorization": f"Bearer {os.environ['FTAI_KEY']}"}
task = requests.post(f"{base}/videos", headers=headers,
json={"model": "MODEL_ID", "prompt": "Waves rolling onto a beach at sunset", "seconds": 8}).json()
while task["status"] in ("queued", "in_progress"):
time.sleep(10)
task = requests.get(f"{base}/videos/{task['id']}", headers=headers).json()
if task["status"] == "completed":
video = requests.get(f"{base}/videos/{task['id']}/content", headers=headers)
open("video.mp4", "wb").write(video.content)import { writeFile } from 'node:fs/promises'
const base = 'https://api.freetheai.org/v1'
const headers = { 'Authorization': `Bearer ${process.env.FTAI_KEY}`, 'Content-Type': 'application/json' }
let task = await (await fetch(`${base}/videos`, {
method: 'POST', headers, body: JSON.stringify({ model: 'MODEL_ID', prompt: 'Waves rolling onto a beach at sunset', seconds: 8 }),
})).json()
while (task.status === 'queued' || task.status === 'in_progress') {
await new Promise(resolve => setTimeout(resolve, 10000))
task = await (await fetch(`${base}/videos/${task.id}`, { headers })).json()
}
if (task.status === 'completed') {
const video = await fetch(`${base}/videos/${task.id}/content`, { headers })
await writeFile('video.mp4', Buffer.from(await video.arrayBuffer()))
}| Field | Type | Description |
|---|---|---|
model | string | A video model ID from GET /v1/models ("type": "video"). |
prompt | string | What to show. |
seconds | integer | Optional. Length of the video (for example 4, 8, or 12); 4 when left out. |
size | string | Optional. For example 1280x720, when the model supports it. |
The create call answers at once with the task ("object": "video", "status": "queued", and a poll_url).
Get the video
Poll GET /v1/videos/{id} every 10 seconds or so. status moves from queued to in_progress to completed or failed; progress counts to 100. A completed task carries content_url; download the MP4 from GET /v1/videos/{id}/content. A failed one carries error with a code and a message.
The request holds the price of the seconds you ask for. You are charged for the seconds delivered, never more than you asked for; a failed or expired task costs nothing.
Errors
| Status | Meaning |
|---|---|
400 | A field has a value the endpoint does not take (the message names it). |
401 | Missing or invalid API key. |
402 | Not enough wallet balance, or the key's budget is used (paid usage errors). |
404 | No model has that ID, none of the providers you follow serve it, or the task ID is not yours. |
503 | The provider is busy. Retry; nothing is charged. |

