Videos
The Videos API generates a video clip from a text prompt, optionally conditioned on uploaded media — one or two images as first/last frames, or reference images, video clips, and audio clips. Rendering takes minutes rather than seconds, so it is an asynchronous job resource: you create a job, poll it until it reaches a terminal status, then download the output.
POST /v1/videosGET /v1/videosGET /v1/videos/modelsGET /v1/videos/acceptancePOST /v1/videos/acceptanceGET /v1/videos/{video_id}GET /v1/videos/{video_id}/contentOutput is MP4 with audio at 768p. Every request must specify aspect_ratio.
Japanese scene descriptions are translated to English before generation. The translator is instructed to leave dialogue inside <d>…</d> and text depicted in the scene unchanged.
Agreement
Section titled “Agreement”A person must agree to the Video Service Terms in the console playground before they can start a job. After that, an API key used by that same person works. A teammate who has not agreed cannot start a job, even in the same organization.
Creating a job never records agreement. The only way to record it is POST /v1/videos/acceptance from a console login. An API key cannot agree.
GET /v1/videos/acceptance returns the current terms version and whether this person, in this organization, has agreed to it.
A missing agreement returns 403 with code agreement_required. Listing jobs, reading a job, and listing models stay open.
Create a job
Section titled “Create a job”curl https://api.aiand.com/v1/videos \ -H "Authorization: Bearer $AIAND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-h3", "prompt": "A paper boat drifting down a rain-soaked gutter at dusk", "seconds": 8, "aspect_ratio": "16:9" }'| Field | Required | Notes |
|---|---|---|
model | yes | A model id from GET /v1/videos/models |
prompt | yes | Up to 7000 characters |
seconds | yes | Clip duration, 4–15 |
aspect_ratio | yes | One of Auto, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16 |
image_reference | no | One or two images (purpose: "vision") with unique first_frame/last_frame roles (image-to-video) |
references | no | Reference media to condition on (reference-to-video): images, videos, audio. Cannot be combined with image_reference |
First and last frame (image-to-video)
Section titled “First and last frame (image-to-video)”Upload each image first and use the returned file_id. Each image must be purpose: "vision" and under 30 MiB — the engine rejects larger inputs even though the Files API accepts uploads up to 100 MB.
curl https://api.aiand.com/v1/files \ -H "Authorization: Bearer $AIAND_API_KEY" \ -F "purpose=vision" \ -F "file=@first.jpg"Then submit one or two file references in customer-defined order:
curl https://api.aiand.com/v1/videos \ -H "Authorization: Bearer $AIAND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-h3", "prompt": "A cinematic scene inspired by the references, natural motion", "seconds": 5, "aspect_ratio": "16:9", "image_reference": [ { "file_id": "file-first", "role": "first_frame" }, { "file_id": "file-last", "role": "last_frame" } ] }'The API validates that every file belongs to your organization and has purpose: "vision". It converts the stored R2 objects to short-lived signed URLs immediately before engine submission; public URLs are never required. Either role may be used alone, so a single first_frame does not require a last_frame. When both are supplied, their roles must be unique.
Reference images, video, and audio (reference-to-video)
Section titled “Reference images, video, and audio (reference-to-video)”To condition on reference media instead of frames, upload each file with the matching purpose — vision for images, video for clips, audio for sound — and pass the file_ids inside a references object:
curl https://api.aiand.com/v1/videos \ -H "Authorization: Bearer $AIAND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-h3", "prompt": "A cinematic scene inspired by the references, natural motion", "seconds": 5, "aspect_ratio": "16:9", "references": { "images": [{ "file_id": "file-img1" }], "videos": [{ "file_id": "file-clip1" }], "audio": [{ "file_id": "file-aud1" }] } }'Counts and per-file sizes are validated at request time; video and audio references must also be 2–15 seconds long (enforced by the engine).
| Reference | Purpose | Max count | Max size | Duration |
|---|---|---|---|---|
| image | vision | 8 | 30 MiB | — |
| video | video | 2 | 50 MiB | 2–15 s |
| audio | audio | 3 | 15 MiB | 2–15 s |
Two rules apply:
- Frames and references cannot be mixed. A request uses
image_referenceorreferences— never both. They are separate request shapes. - Audio needs an anchor.
referencesmust include at least one image or video; audio alone is rejected.
The response is a job object with status: "moderating":
{ "id": "video_9f2c1b7e4a3d4e8fa1b0c9d8e7f6a5b4", "object": "video", "model": "minimaxai/minimax-h3", "prompt": "A paper boat drifting down a rain-soaked gutter at dusk", "seconds": 8, "status": "moderating", "error": null, "cost": "0.64000000", "currency": "usd", "created_at": 1755302400, "completed_at": null}status is one of moderating, translating, queued, in_progress, completed, failed, or canceled. Treat any status you do not recognize as still running — new intermediate stages may be added. error is populated only when the job failed.
Input moderation
Section titled “Input moderation”Every job starts as moderating while its prompt and reference media are checked against our content policy. This normally takes a few seconds — up to about a minute when references are attached — and allowed jobs move to translating while the prompt is translated to English, then to queued, and render as usual. A request that violates the policy fails with error code moderation_blocked and is never billed:
{ "status": "failed", "error": { "code": "moderation_blocked", "message": "Your request was rejected by our content moderation system." }}If the moderation system itself is unavailable, the job fails closed with error code moderation_unavailable — nothing was judged and nothing is billed, so resubmit later. Likewise, if a Japanese prompt cannot be translated, the job fails closed with error code translation_unavailable — nothing is billed, so resubmit later.
Poll for completion
Section titled “Poll for completion”curl https://api.aiand.com/v1/videos/video_9f2c1b7e4a3d4e8fa1b0c9d8e7f6a5b4 \ -H "Authorization: Bearer $AIAND_API_KEY"A typical clip takes several minutes. Poll every 10–30 seconds until status is terminal — polling faster does not make a render finish sooner.
Download the output
Section titled “Download the output”Once status is completed, fetch the bytes. The response is the raw MP4, not JSON:
curl https://api.aiand.com/v1/videos/video_9f2c1b7e4a3d4e8fa1b0c9d8e7f6a5b4/content \ -H "Authorization: Bearer $AIAND_API_KEY" \ -o clip.mp4Requesting content for a job that is not completed returns 400.
List your jobs
Section titled “List your jobs”curl "https://api.aiand.com/v1/videos?limit=20" \ -H "Authorization: Bearer $AIAND_API_KEY"Returns newest first. limit defaults to 20 and caps at 100; pass after=<video_id> to page.
List video models
Section titled “List video models”curl https://api.aiand.com/v1/videos/models \ -H "Authorization: Bearer $AIAND_API_KEY"Each entry carries per-second pricing in your billing currency, one row per output resolution:
{ "object": "list", "data": [ { "id": "minimaxai/minimax-h3", "object": "video_model", "name": "MiniMaxAI/MiniMax-H3", "description": "MiniMax H3", "pricing": [{ "resolution": "768p", "per_second": "0.080000", "currency": "usd" }] } ]}Billing
Section titled “Billing”A render is priced as per_second × seconds and charged only when it completes. A job that fails, times out, or is canceled is never charged.
Because a render costs dollars and cannot be aborted part-way, its exact cost is fixed when the job is submitted: per_second × requested seconds. A job is refused unless your balance covers that quote plus the quoted costs of renders already in flight. This is stricter than the chat endpoints, which admit any request while the balance is above zero.
cost and currency contain that quote from the first response. The balance is deducted only after the render completes successfully.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
400 | invalid_request_error | Bad body, out-of-range seconds, invalid or oversized references, or content requested before completion |
403 | agreement_required | This person has not agreed to the current Video Service Terms in the console playground |
402 | insufficient_credits | Balance does not cover the quoted cost of this render |
404 | model_not_found | Unknown model, or one your plan is not entitled to |
429 | concurrency_limit_exceeded | You already have the maximum number of renders in progress for your plan |
409 | conflict | The job is still running, or is under review and cannot be deleted |
Retention and deletion
Section titled “Retention and deletion”A finished job — the generated video and the job record, including its prompt — is deleted automatically 30 days after it finishes. Download anything you want to keep before then.
DELETE /v1/videos/{video_id} deletes one immediately:
curl -X DELETE https://api.aiand.com/v1/videos/video_abc123 \ -H "Authorization: Bearer $AIAND_API_KEY"{ "id": "video_abc123", "object": "video", "deleted": true }This is permanent and cannot be undone. A job that is still running has to finish first — poll it until its status is terminal, then delete.