API > Integrate API into your product
Video Generation API
Base URL: https://api.phantaisia.com
All requests require a Bearer token in the Authorization header.
Authorization: Bearer <your_token>
Overview
There are two ways to generate a video:
| Endpoint | What it does |
|---|---|
POST /v1/run/single_frame_video |
Animate a single image — you provide one photo and a text prompt |
POST /v1/run/first_last_frame_video |
Transition between two images — you provide a first and last frame |
Both endpoints return a job ID immediately. Use the shared status endpoint to poll until the video is ready.
Models
Both run endpoints accept a model parameter that controls quality and speed.
| Model | Description |
|---|---|
simple |
Fastest generation, good for previews. Single frame only. 4s only. |
advanced |
Higher quality, recommended for final output |
performance |
Highest quality, supports custom aspect ratios. Single frame only. |
For credit costs per model and duration, see Video Generation Pricing.
1. Single Frame Video
POST /v1/run/single_frame_video
Animates a single image using a text prompt. The image becomes the starting frame of the video.
Request body
{
"prompt_image": "<base64-or-url>",
"prompt": "The subject waves and smiles at the camera.",
"model": "advanced",
"duration": "4s",
"aspect_ratio": "auto"
}
| Field | Type | Required | Description |
|---|---|---|---|
prompt_image |
string |
Yes | Starting image as a base64 data URI (data:image/jpeg;base64,...) or a publicly accessible URL |
prompt |
string |
Yes | Text description of the motion or scene you want generated |
model |
string |
Yes | "simple", "advanced", or "performance" — see Models table above |
duration |
string |
Yes | Video length: "4s", "6s", or "8s". simple model only supports "4s". |
aspect_ratio |
string |
No (default: "auto") |
Output aspect ratio — only supported with performance model. Options: "auto", "16:9", "9:16", "3:2", "2:3" |
Response — 200 OK
{
"id": "job-abc123",
"status": "IN_QUEUE"
}
Use the id to poll the status endpoint.
Errors
| HTTP | error_code |
Meaning |
|---|---|---|
402 |
— | Insufficient credits |
422 |
INVALID_ASPECT_RATIO_FOR_MODEL |
A non-"auto" aspect ratio was requested with a model other than "performance" |
422 |
INVALID_VIDEO_MODEL |
The model value is not recognised |
2. First-Last Frame Video
POST /v1/run/first_last_frame_video
Generates a video that transitions between two images. The model interpolates the motion between your first and last frame guided by your prompt.
Note: Only the
advancedmodel is available for this endpoint.simpleandperformanceare single-frame only.
Request body
{
"prompt": "The subject smoothly transitions from the first frame to the last frame.",
"model": "advanced",
"duration": "8s",
"first_frame": "<base64-or-url>",
"last_frame": "<base64-or-url>"
}
| Field | Type | Required | Description |
|---|---|---|---|
first_frame |
string |
Yes | Opening frame of the video — base64 data URI or public URL |
last_frame |
string |
Yes | Closing frame of the video — base64 data URI or public URL |
prompt |
string |
Yes | Text description of the transition or action between the two frames |
model |
string |
Yes | Must be "advanced" |
duration |
string |
Yes | Video length: "4s", "6s", or "8s" |
Response — 200 OK
{
"id": "job-xyz789",
"status": "IN_QUEUE"
}
Use the id to poll the status endpoint.
Errors
| HTTP | error_code |
Meaning |
|---|---|---|
402 |
— | Insufficient credits |
422 |
INVALID_VIDEO_MODEL |
The model value is not recognised, or "simple" / "performance" was specified (not supported for this endpoint) |
3. Check Job Status
POST /v1/status/single_frame_video/{job_id}
Used to check the status of both single-frame and first-last-frame video jobs. This endpoint is non-blocking — it returns the current state immediately. Keep polling until the job reaches a terminal status (COMPLETED or FAILED).
Recommended polling interval: every 5–10 seconds. Video jobs typically take 1–3 minutes.
Path parameter
| Parameter | Type | Description |
|---|---|---|
job_id |
string |
The id returned from the run endpoint |
Response — in progress
{
"id": "job-abc123",
"status": "IN_PROGRESS",
"output": {}
}
Response — completed
{
"id": "job-abc123",
"status": "COMPLETED",
"output": {
"video_url": "https://...",
"video_status": "completed"
}
}
Response — failed
{
"id": "job-abc123",
"status": "FAILED",
"output": {
"video_status": "failed",
"video_error": "VEO generation failed"
}
}
Status values
| Status | Terminal | Meaning |
|---|---|---|
IN_QUEUE |
No | Job is queued, not yet started |
IN_PROGRESS |
No | Job is actively generating |
COMPLETED |
Yes | Video is ready — output.video_url contains the download link |
FAILED |
Yes | Generation failed — stop polling, output.video_error has details |
End-to-end example (JavaScript)
const TOKEN = 'your_token_here';
const BASE = 'https://api.phantaisia.com';
async function generateVideo(endpoint, body) {
// 1. Submit job
const runRes = await fetch(`${BASE}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${TOKEN}`,
},
body: JSON.stringify(body),
});
if (!runRes.ok) throw new Error(`Submit failed: ${await runRes.text()}`);
const { id } = await runRes.json();
console.log('Job submitted:', id);
// 2. Poll for result
while (true) {
await new Promise(r => setTimeout(r, 7000));
const statusRes = await fetch(`${BASE}/v1/status/single_frame_video/${id}`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${TOKEN}` },
});
if (!statusRes.ok) throw new Error(`Status error: ${await statusRes.text()}`);
const data = await statusRes.json();
console.log('Status:', data.status);
if (data.status === 'COMPLETED') {
return data.output.video_url;
}
if (data.status === 'FAILED') {
throw new Error(data.output?.video_error ?? 'Generation failed');
}
}
}
// Single frame example
const videoUrl = await generateVideo('/v1/run/single_frame_video', {
prompt_image: 'https://example.com/photo.jpg',
prompt: 'The subject turns and smiles.',
model: 'advanced',
duration: '4s',
});
// First-last frame example
const videoUrl2 = await generateVideo('/v1/run/first_last_frame_video', {
first_frame: 'https://example.com/start.jpg',
last_frame: 'https://example.com/end.jpg',
prompt: 'Smooth transition from standing to sitting.',
model: 'advanced',
duration: '8s',
});