Authorizationstring · headerrequiredOpen API v1 · Seedance 2.0
Put video generation behind your product
AiuniVid Open API is an asynchronous generation gateway. Create returns a task ID immediately. The website and API share the same credit ledger. It exposes Seedance 2.5 and Seedance 2.0 across text, image, and reference modes; 2.0 also has Fast and Mini tiers — twelve public model IDs.
- Text-to-Video: Generate from a text description.
- Image-to-Video: Use 1–2 images as first or first-and-last frames.
- Reference-to-Video: Use images, video, and audio as multimodal references.
Quickstart
Any signed-in user can create an av_live_ key in Developer Center. The secret is shown once — store it on your server.
- 1. Set environment variables
export AIUNIVID_BASE_URL=https://aiunivid.com/api/open export AIUNIVID_API_KEY=av_live_xxx - 2. Quote credits (optional, no charge)
POST the same body to /v1/videos/generations/quote and read data.credits_to_hold. - 3. Create the task
POST /v1/videos/generations with a required Idempotency-Key. Success is 202 plus a task id. Replaying the same key and body does not charge twice. - 4. Poll or receive a webhook
GET /v1/videos/generations/{id} until status is succeeded or failed — or pass callback_url on create. On success, use result.download_url.
Integrate into your video product
Keep AiuniVid behind your backend. Users talk only to your product; your service owns the API key and task sync.
Product UI
Submits prompt, model, and media.
Your backend
Validates the user, stores a record, then calls AiuniVid.
AiuniVid API
Returns 202 and a task ID.
Result page
Reads your task status and plays the video.
Rate limits
Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix seconds). Exceeding the limit returns 429 rate_limit_exceeded.
| Class | Endpoints | Limit |
|---|---|---|
| Create endpoints | POST /v1/videos/generations, /quote | 10 requests / minute / key |
| Read endpoints | GET /v1/models, /v1/credits/balance, /v1/videos/generations, /v1/videos/generations/{id} | 60 requests / minute / key |
Models and capabilities
GET /v1/modelsendpoint{
"success": true,
"request_id": "req_xxx",
"data": {
"models": [
{
"id": "seedance-2.0-text-to-video",
"name": "Seedance 2.0 Text-to-Video",
"mode": "text-to-video",
"tier": "standard",
"durations": [5, 8, 10],
"aspect_ratios": ["16:9", "9:16", "1:1"],
"qualities": ["480p", "720p", "1080p"],
"capabilities": {
"text_to_video": true,
"generate_audio": true,
"max_images": 0,
"max_videos": 0,
"max_audios": 0
}
}
]
}
}Quote a generation
POST /v1/videos/generations/quoteendpoint{
"success": true,
"request_id": "req_01JQ9X2B6XK9K4VQY2QZ4H6W3R",
"data": {
"model": "seedance-2.5-text-to-video",
"credits_to_hold": 50,
"currency_note": "credits"
}
}Create a generation
POST /v1/videos/generationsendpointrequiredmodelenum<string>required| Model ID | Mode | Tier |
|---|---|---|
| seedance-2.5-text-to-video | text-to-video | standard |
| seedance-2.5-image-to-video | image-to-video | standard |
| seedance-2.5-reference-to-video | reference-to-video | standard |
| seedance-2.0-text-to-video | text-to-video | standard |
| seedance-2.0-image-to-video | image-to-video | standard |
| seedance-2.0-reference-to-video | reference-to-video | standard |
| seedance-2.0-fast-text-to-video | text-to-video | fast |
| seedance-2.0-fast-image-to-video | image-to-video | fast |
| seedance-2.0-fast-reference-to-video | reference-to-video | fast |
| seedance-2.0-mini-text-to-video | text-to-video | mini |
| seedance-2.0-mini-image-to-video | image-to-video | mini |
| seedance-2.0-mini-reference-to-video | reference-to-video | mini |
promptstringrequiredimage_urlsstring<uri>[]video_urls / audio_urlsstring<uri>[]durationintegerqualityenum<string>aspect_ratioenum<string>generate_audiobooleancallback_urlstring<uri>metadataobjectTask management
GET /v1/videos/generations/{id}endpointGET /v1/videos/generationsendpoint{
"success": true,
"request_id": "req_xxx",
"data": {
"tasks": [{ "id": "vid_01JQ9X2B6XK9K4VQY2QZ4H6W3R", "status": "succeeded" }],
"next_cursor": null
}
}POST /v1/videos/generations/{id}/cancelendpointUpload reference media
POST /v1/uploads/presignendpoint{
"success": true,
"request_id": "req_xxx",
"data": {
"upload_url": "https://aiunivid.com/api/open/v1/uploads/put?key=api-uploads/...&sig=...",
"public_url": "https://cdn.example.com/api-uploads/user/file.png",
"expires_at": 1761314644,
"headers": { "Content-Type": "image/png" },
"method": "PUT"
}
}Credit balance
GET /v1/credits/balanceendpointBilling
The website and API use the same markup for the same user. 1 credit = $0.01.
| Stage | Behavior |
|---|---|
| quote | No charge; returns credits_to_hold |
| create | Reserves credits_reserved |
| succeeded | Settles credits_settled |
| failed / cancelled | Releases the hold as credits_refunded |
Webhooks
Pass callback_url on create. AiuniVid POSTs the full task object when the task reaches succeeded, failed, or cancelled.
X-AiuniVid-EventheaderX-AiuniVid-SignatureheaderNode
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyAiuniVidSignature(header, rawBody, secret) {
const parts = Object.fromEntries(
header.split(",").map((item) => item.split("="))
);
const age = Math.abs(Date.now() / 1000 - Number(parts.t));
if (age > 300) throw new Error("Signature timestamp is stale");
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
if (
!timingSafeEqual(Buffer.from(parts.v1, "utf8"), Buffer.from(expected, "utf8"))
) {
throw new Error("Invalid signature");
}
}Python
import hmac, hashlib, time
def verify_aiunivid_signature(header: str, raw_body: str, secret: str) -> None:
parts = dict(item.split("=", 1) for item in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
raise ValueError("Signature timestamp is stale")
expected = hmac.new(
secret.encode(),
f'{parts["t"]}.{raw_body}'.encode(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(parts["v1"], expected):
raise ValueError("Invalid signature")Delivery times out after 10 seconds. Non-2xx responses are retried with exponential backoff (1s, 2s, 4s, 8s, …) for up to 24 hours. Always return 2xx to acknowledge the event.
Advanced compatibility path
The primary path is /v1/videos/generations. If you already integrated BytePlus-style content[] payloads, /v1/contents/generations/tasks (and its quote endpoint) remains available. New integrations should not use this path.
POST /v1/contents/generations/tasksendpointError handling
Branch on the stable error.code, not the message text. 500 is safe to retry with the same Idempotency-Key.
| HTTP | error.code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed request body or fields |
| 400 | unsupported_model | Model ID is not one of the public IDs |
| 401 | invalid_api_key | Key is invalid, expired, or revoked |
| 402 | insufficient_credits | Not enough available credits |
| 403 | insufficient_scope | Key lacks the required scope |
| 403 | task_cancel_not_allowed | Task cancellation is not supported |
| 404 | task_not_found | Task does not exist or is not owned by this key |
| 409 | idempotency_conflict | Same Idempotency-Key reused with a different body |
| 422 | unsupported_capability | Fields exceed the model's capability |
| 422 | unsafe_input | Media or callback URL is not a public HTTPS address |
| 429 | rate_limit_exceeded | Rate limit exceeded |
| 429 | too_many_concurrent_jobs | In-flight generation jobs exceeded the account limit |
| 500 | internal_error | Retry with the same Idempotency-Key |
Machine-readable contract: openapi.yaml · api-reference.md · llms.txt