Generate AI video, images, and chat through an OpenAI-compatible API. If you already use the OpenAI SDK, change one line — the base_url.
sk- key in the console API Keyshttps://api.perseworks.hk/v1Video is async — submit returns a task id; poll it until it succeeds.
curl https://api.perseworks.hk/v1/video/generations \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0",
"prompt": "a cat surfing a wave, cinematic",
"resolution": "1080p",
"durationSec": 5
}' import requests
r = requests.post(
"https://api.perseworks.hk/v1/video/generations",
headers={"Authorization": "Bearer sk-..."},
json={
"model": "seedance-2.0",
"prompt": "a cat surfing a wave, cinematic",
"resolution": "1080p",
"durationSec": 5,
},
)
task = r.json()
print(task["id"], task["status"]) # vid_... queued const res = await fetch("https://api.perseworks.hk/v1/video/generations", {
method: "POST",
headers: {
"Authorization": "Bearer sk-...",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "seedance-2.0",
prompt: "a cat surfing a wave, cinematic",
resolution: "1080p",
durationSec: 5,
}),
});
const task = await res.json();
console.log(task.id, task.status); // vid_... queued resolution: 720p · 1080p · 4K (1080p and 4K on Seedance 2.0 only; Fast/Mini are 720p).
aspectRatio: 16:9 · 4:3 · 1:1 · 3:4 · 9:16 · 21:9 · adaptive.
durationSec: up to 15.
image: optional reference-image URL for image-to-video.
curl https://api.perseworks.hk/v1/video/generations/vid_... \
-H "Authorization: Bearer sk-..."
# → { "status": "running" } (keep polling)
# → { "status": "succeeded", "video_url": "https://...", "duration": 5 } r = requests.get(
f"https://api.perseworks.hk/v1/video/generations/{task_id}",
headers={"Authorization": "Bearer sk-..."},
)
print(r.json())
# {"status": "succeeded", "video_url": "https://...", "duration": 5} const r = await fetch(`https://api.perseworks.hk/v1/video/generations/${id}`, {
headers: { "Authorization": "Bearer sk-..." },
});
console.log(await r.json());
// { status: "succeeded", video_url: "https://...", duration: 5 } Images are synchronous — one call returns the result URL(s). Powered by Seedream 5.0 Pro.
curl https://api.perseworks.hk/v1/images/generations \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-5.0",
"prompt": "a red panda barista, cinematic lighting",
"size": "2K"
}' import requests
r = requests.post(
"https://api.perseworks.hk/v1/images/generations",
headers={"Authorization": "Bearer sk-..."},
json={
"model": "seedream-5.0",
"prompt": "a red panda barista, cinematic lighting",
"size": "2K",
},
)
print(r.json()["data"][0]["url"]) # https://... const res = await fetch("https://api.perseworks.hk/v1/images/generations", {
method: "POST",
headers: {
"Authorization": "Bearer sk-...",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "seedream-5.0",
prompt: "a red panda barista, cinematic lighting",
size: "2K",
}),
});
const out = await res.json();
console.log(out.data[0].url); // https://... size: 1K · 2K · 3K · 4K, or an explicit WxH (e.g. 1024x1024).
image: optional reference image(s) — URL or base64, up to 10 — for image-to-image / multi-reference.
n: 1–4 images.
seed: reproducible.
Response — the generated image URL(s):
{
"model": "seedream-5.0",
"created": 1785000000,
"data": [ { "url": "https://.../out.png" } ],
"usage": { "images": 1 }
} curl https://api.perseworks.hk/v1/chat/completions \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "seed-2.0-mini",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}' from openai import OpenAI
client = OpenAI(api_key="sk-...", base_url="https://api.perseworks.hk/v1") # change only this line
stream = client.chat.completions.create(
model="seed-2.0-mini",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="") import OpenAI from "openai";
const client = new OpenAI({ apiKey: "sk-...", baseURL: "https://api.perseworks.hk/v1" }); // change only this
const stream = await client.chat.completions.create({
model: "seed-2.0-mini",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0].delta.content || "");
} Pass the model id in your request. The live list is always GET /v1/models.
seedance-2.5 video 480p / 720p · flagship · multimodal (text/image/video/audio) → video · reference · edit · extend · up to 30s seedance-2.0 video 720p / 1080p / 4K · text + image to video · audio seedance-2.0-fast video 720p · faster generation seedance-2.0-mini video 720p · lowest cost seedream-5.0 image Seedream 5.0 Pro · text-to-image + editing · 1K or 2K · flat rate seed-2.1-pro chat strongest chat model · 262K context seed-2.0-mini chat fast + low cost · 262K context Embeddings and audio are on the roadmap.
/v1/video/generations Submit a Seedance video job /v1/video/generations/:id Poll a video job for its result /v1/models List available models /v1/chat/completions Chat completion (supports stream: true) /v1/images/generations Generate Seedream images Embeddings and audio endpoints are on the roadmap.
Every error returns the same JSON shape alongside an HTTP status code:
{ "error": { "code": "invalid_request", "message": "a human-readable reason" } } 400 · invalid_request Malformed body or a missing required field 400 · content_blocked Prompt failed content moderation (never charged) 401 · invalid_api_key Missing, unknown, or revoked API key 402 · insufficient_points Not enough points to reserve the request 403 · model_not_allowed This key is not scoped to that model 404 · not_found Task not found, or not owned by this key 413 · payload_too_large Request body exceeds the size cap 429 · rate_limited Per-key rate limit exceeded — back off and retry 5xx · upstream_error / internal_error Server or vendor error — the charge is refunded GET /v1/models.429 rate_limited. Back off and retry.Idempotency-Key header on a video submit so a retry returns the same task instead of starting a new job.