Generate AI videos and images programmatically via our REST API.
For AI coding assistants and tools: api.md (the whole reference in Markdown) · openapi.json (OpenAPI 3.1)
All API requests require a Bearer token. Create an API key in your Developer Options page.
Authorization: Bearer okpk_your_api_key_here
Prices for every model and option are on the Pricing page.
| Model ID | Label | Duration | Ratios |
|---|---|---|---|
| minimax-h3 | MiniMax H3HOT | 1–15s | 16:9, 9:16 |
| seedance-2.5 | Seedance 2.5 | 4–30s | 16:9, 9:16, 1:1 |
| seedance-2.0 | Seedance 2.0 | 4–15s | 16:9, 9:16, 1:1 |
| seedance-2.0-mini | Seedance 2.0 Mini | 4–15s | 16:9, 9:16, 1:1 |
| veo3.1 | Veo 3.1 | — | 16:9, 9:16 |
Model ID minimax-h3. Four modes via ref_mode. Ratios: 16:9, 9:16. Every mode is billed per second of output video at the resolution's rate.
| ref_mode | Inputs | Notes |
|---|---|---|
| omni | media: up to 9 images + 3 audio clips | Default. Refer to images in the prompt as <Picture 1>, audio as <Audio 1>. |
| first-last | first_frame (required) + last_frame (optional) | media is not accepted. 480p / 768p only. |
| okay HOT | first_frame / last_frame + media, all optional | Omni reference with locked frames — see below. |
| lip-sync | media: exactly 1 image + 1 audio | Audio-driven talking video — see below. |
effort) — pay for a better renderOptional, defaults to "1x". Leave it out and nothing changes. Higher tiers put more work into each video: more detail, and the model follows a multi-shot prompt more closely — at 1x it sometimes skips a cut the prompt explicitly asks for.
| effort | Price | Notes |
|---|---|---|
| 1x | base rate | Default — what every request got before this option existed. |
| 1.5x | +30% (768p: $0.013/s) | Runs on our own GPUs only, so it can queue at busy times. |
| 2x | +60% (768p: $0.016/s) | Runs on our own GPUs only, so it can queue at busy times. |
Renders take noticeably longer — roughly 1.4x at 1.5x and 1.9x at 2x, more when demand is high. Works in every ref_mode at 480p and 768p. 1080p has no tiers — sending one returns 400.
ref_mode: "okay") — omni reference with locked frames HOTH3-only. Pin the video's opening and/or closing frame with first_frame / last_frame while still using reference images (<Picture N>) and audio (voice timbre) from media.
<Picture N> counts only the images in media.ref_mode: "lip-sync")media must be exactly one image and one audio clip. The image is the locked first frame; the audio is used as the video's soundtrack and drives the lips.duration only to cut it shorter. Billed per output second.prompt is optional — use it to say who is speaking (when the image has several people) or how they move.| resolution | Duration | Modes |
|---|---|---|
| 480p | 1–15s | omni, first-last, okay, lip-sync |
| 768p | 1–15s | omni, first-last, okay, lip-sync |
| 1080p | 1–10s | omni, okay (without frames), lip-sync |
Choose resolution and tier. third-party is the low-cost channel; official is the quality channel (a cheaper channel of the same model is tried first and a failed render is retried on the next one). Not every model has both tiers: asking for one it doesn't have returns 400. Billed seconds = duration + total reference-video seconds.
| Model ID | resolution | tier | Duration | Max refs (img / video / audio) |
|---|---|---|---|---|
| seedance-2.5 | 720p | official | 4–30s | 30 / 10 (30s) / 10 (30s) |
| seedance-2.5 | 480p | third-party | 4–30s | 30 / 10 (30s) / 10 (30s) |
| seedance-2.5 | 480p | official | 4–30s | 30 / 10 (30s) / 10 (30s) |
| seedance-2.0 | 720p | third-party | 4–15s | 9 / 3 (15s) / 3 (15s) |
| seedance-2.0-mini | 720p | official | 4–15s | 9 / 3 (15s) / 3 (15s) |
| Variant ID | Label | Max Images |
|---|---|---|
| veo3.1-fast | Fast | 2 |
| veo3.1-components | Components | 3 |
| veo3.1-pro | Pro | 2 |
| Model ID | Label | Ratios | Resolutions |
|---|---|---|---|
| doubao-seedream-5.0 | Seedream 5.0 | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9 | 1k, 2k, 4k |
| gpt-image-2.5 | GPT Image 2.5 | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 | 1k, 2k, 4k |
| nano-banana-2.1 | Nano Banana 2.1 | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 | — |
| gpt-image-2 | GPT Image 2 | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 | — |
| gemini-3-pro-image-preview | Gemini 3 Pro Image | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9 | — |
| gemini-3.1-flash-image-preview | Gemini 3.1 Flash Image | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9 | — |
| gemini-2.5-flash-image | Gemini 2.5 Flash Image | 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 | — |
/api/video/generateSubmit a video generation task. For image models use POST /api/image/generate (see below). Send an Idempotency-Key header so retries never create a second task (see Idempotency below).
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | Video model ID (see models table) |
| prompt | string | Yes* | Text description of the video to generate. *Optional for MiniMax H3 lip-sync |
| duration | number | No | Video duration in seconds (model-dependent range) |
| ratio | string | No | Aspect ratio (e.g. "16:9", "9:16", "1:1") |
| variant | string | No | For Veo 3.1 only: variant ID (see variants table) |
| resolution | string | No | Seedance: "480p" / "720p" (default) / "1080p", where available. MiniMax H3: "480p" / "768p" (default) / "1080p" |
| ref_mode | string | No | MiniMax H3 only: "omni" (default), "first-last", "okay" or "lip-sync" |
| first_frame / last_frame | string | No | MiniMax H3 first-last and okay modes: the opening / closing frame (public https URL or base64 image data URI). Rejected in other modes. |
| optimize_prompt | boolean | No | MiniMax H3 only, default false. When true, an LLM rewrites your prompt into H3's official structured format (subject_definitions, shots, sound), using your reference images and audio. Prompts already in that format are used unchanged; if the rewrite fails the original prompt is used. No extra charge. |
| seed | integer | No | MiniMax H3 only: 0–2147483647. Different seeds give different results. The same seed is not guaranteed to reproduce the same output — generations may run on different machines. Sending seed to any other model returns 400 (it is never silently ignored). |
| tier | string | No | Seedance only: "third-party" (default when available) or "official" |
| media | array | No | Reference media array. Each item: {type: "image"|"video"|"audio", url: "..."} — url is a public https URL or, for images and audio, a base64 data URI (see Reference media below). Constraints depend on model / resolution / tier. |
media (omni reference). Limits per resolution / tier are in the Seedance table above.jimeng-video-seedance-2.0 still works and maps to seedance-2.0. Seedance 2.0 Fast is no longer available. ref_mode is ignored.veo3.1-fast and is charged that price. No ref_mode needed.{
"generationId": "3f6c…",
"taskId": "3f6c…", // same as generationId — use it to poll
"status": "pending"
}/api/video/tasks/{taskId}Poll a task for its current status and results. /api/image/tasks/{taskId} works the same way for image tasks. Poll every 5–10 s; repeated polls within 5 s return the same cached status.
{
"status": "completed",
"resultUrls": ["https://cdn.example.com/video.mp4"],
"type": "video"
}{
"status": "processing",
"progress": 50,
"type": "video"
}{
"status": "failed",
"errorMessage": "Content policy violation: …",
"errorCode": "content_violation",
"retryable": false,
"type": "video"
}Failed tasks are always refunded. Branch on errorCode / retryable, not on the message text:
| errorCode | retryable | Meaning |
|---|---|---|
| content_violation | false | The provider flagged the prompt or reference media. Retrying the same input will fail again. Only set when the provider says so explicitly (currently MiniMax H3 and Gemini / GPT Image via our image channel). |
| generation_failed | true | The provider failed for another reason (for Seedance, after trying every available channel). Retrying may succeed. |
| no_result | true | The provider reported success but returned no file, or it could not be saved. |
| timeout | true | No result within 6 hours. |
/api/image/generateSubmit an image generation task with an image model (see Image Models). Body fields: model, prompt, ratio, resolution (models that list resolutions), and images — an array of reference images (public https URLs or base64 data URIs). Some models answer immediately with "status": "completed" and resultUrls; otherwise poll GET /api/image/tasks/{taskId}.
curl -X POST https://api.okaypic.com/api/image/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "gemini-3.1-flash-image-preview", "prompt": "A red fox in the snow", "ratio": "1:1"}'{
"generationId": "…",
"taskId": "…",
"status": "pending" // or "completed" with "resultUrls": ["https://…"]
}Both generate endpoints accept a client-chosen unique id per task, either as the Idempotency-Key header or as client_request_id in the JSON body (the header wins if both are set; 1–255 characters, scoped to your account).
taskId and its current status, with "idempotentReplay": true. Keep polling that task.status: "failed", refunded), the same key keeps returning that failed task. To generate again, use a new key.curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: 541913da-s01_depot_daily_alert-clip1" \
-H "Content-Type: application/json" \
-d '{"model": "minimax-h3", "prompt": "…", "duration": 5}'
# Same request again (e.g. after a timeout on your side) →
# { "generationId": "3f6c…", "taskId": "3f6c…", "status": "processing", "idempotentReplay": true }Reference files go in media[].url (video endpoint) or images[] (image endpoint), in one of two forms:
https:// and reachable from the internet (no login, no expiring link shorter than an hour). Required for videos.data:image/png;base64,iVBORw0…. Images (jpeg / png / webp) and audio only, ≤ 10 MB each, up to 12 per request, request body ≤ 40 MB. Inline files are kept only for generations that were actually created.import base64, requests
with open("cat.jpg", "rb") as f:
cat = "data:image/jpeg;base64," + base64.b64encode(f.read()).decode()
requests.post("https://api.okaypic.com/api/video/generate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"model": "minimax-h3",
"prompt": "<Picture 1> The cat jumps onto the sofa",
"duration": 5,
"resolution": "768p",
"media": [{"type": "image", "url": cat}],
})RateLimit header telling you when to retry.# 1. Submit a video generation task — MiniMax H3 (our cheapest video model)
curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"prompt": "A cat playing piano in a jazz club",
"duration": 5,
"ratio": "16:9",
"resolution": "768p",
"effort": "1x"
}'
# MiniMax H3 first/last frame
curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"prompt": "Smooth transition from dawn to dusk",
"duration": 5,
"resolution": "768p",
"ref_mode": "first-last",
"first_frame": "https://example.com/first.jpg",
"last_frame": "https://example.com/last.jpg"
}'
# MiniMax H3 Okay mode: omni reference with locked frames — starts on first_frame, ends on
# last_frame, while the <Picture N> references and the audio (voice timbre) are still used
curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"prompt": "<Picture 1> walks into the room and greets the camera",
"duration": 6,
"resolution": "768p",
"ref_mode": "okay",
"first_frame": "https://example.com/start.jpg",
"last_frame": "https://example.com/end.jpg",
"media": [
{"type": "image", "url": "https://example.com/character.jpg"},
{"type": "audio", "url": "https://example.com/voice.mp3"}
]
}'
# MiniMax H3 lip sync: one image + one audio; the audio becomes the soundtrack
curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"ref_mode": "lip-sync",
"resolution": "768p",
"media": [
{"type": "image", "url": "https://example.com/portrait.jpg"},
{"type": "audio", "url": "https://example.com/speech.mp3"}
]
}'
# Seedance: pick resolution + channel tier, with reference media (images / video / audio)
curl -X POST https://api.okaypic.com/api/video/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.5",
"prompt": "Make this cat dance",
"duration": 5,
"ratio": "16:9",
"resolution": "720p",
"tier": "third-party",
"media": [{"type": "image", "url": "https://example.com/cat.jpg"}]
}'
# 2. Poll for task completion
curl https://api.okaypic.com/api/video/tasks/TASK_ID \
-H "Authorization: Bearer YOUR_API_KEY"
# Response: { "status": "completed", "resultUrls": ["https://..."], "type": "video" }| Status | Meaning |
|---|---|
| 400 | Bad request — invalid model, missing parameters, or wrong endpoint for the model type |
| 401 | Unauthorized — invalid or missing API key |
| 402 | Insufficient balance |
| 409 | A request with the same Idempotency-Key is still being processed — retry shortly with the same key |
| 429 | Too many tasks in progress (max 20) or rate limit exceeded |
| 500 | Internal server error — backend generation failed |