API reference
Wire-compatible with the MiniMax video generation API. Video and image generation share the same interface. Runnable code samples are on the home page under the API tab, pre-filled with your key.
Overview
| Base URL | https://h3.oneclickamd.ai |
|---|---|
| Auth | Authorization: Bearer <api-key> |
| Request body | application/json |
| Use | v2 for new code. v1 exists only for existing clients. |
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v2/video_generation | Create a generation task |
| GET | /v2/query/video_generation/{task_id} | Query a task |
| GET | /v1/models | Model capabilities: ratios, duration lattice, pricing · no auth |
| GET | /v1/tasks | Your own tasks, paginated · accepts ?modality=video|image |
| DELETE | /v1/tasks/{task_id} | Delete a task and its media |
| POST | /v1/tasks/{task_id}/cancel | Cancel (queued tasks only) |
| GET | /v1/gallery | Public gallery · no auth · accepts ?modality=video|image |
| GET | /v1/account/credits | Balance and held credits |
Create a task
POST /v2/video_generationImages go through this same endpoint. The word video in the path is inherited from MiniMax wire compatibility and cannot change; what you get is decided by model. There is no separate image_generation endpoint.
Request fields:
| Field | Type | Notes |
|---|---|---|
model | string | The accepted values come from GET /v1/models. Today they are MiniMax-H3 (video) and Qwen-Image-2.1 (images). |
content | array | Required. Exactly one text item, plus optional image_url items |
duration | integer | Video models: 4–15, default 5, snapped to the frame lattice (below). Image models have no duration; any value is clamped to 1 |
aspect_ratio | string | 16:9 · 9:16 · 1:1 · 4:3 · 3:4 · 21:9, default 16:9. Ignored when a first frame image is supplied |
steps | integer | Optional. Denoising steps; the range and default are per model, from the steps field of /v1/models. Out of range is clamped rather than refused, and x_steps in the response is the value in force. Billing is proportional to it: steps / default_steps |
callback_url | string | Optional. POSTed once on a terminal state, same body shape as the query response. Requires an admin-configured host allowlist |
{
"model": "MiniMax-H3",
"duration": 5,
"aspect_ratio": "16:9",
"content": [
{ "type": "text", "text": "a red fox running through fresh snow" }
]
}The same endpoint, for an image:
{
"model": "Qwen-Image-2.1",
"aspect_ratio": "1:1",
"content": [
{ "type": "text", "text": "a red fox asleep in fresh snow" }
]
}No duration: image models clamp it to 1, so leaving it out changes nothing.
200 response — a flat object with a single field:
{ "task_id": "a92b251cf8bd41798322ef47bde849a3" }The content array
Must contain exactly one text item. Image items are optional and determine the task type. The table below is MiniMax-H3's; which kinds a model supports comes from task_types in /v1/models — Qwen-Image-2.1 has only the first row:
| Image items | Task type |
|---|---|
| none | text to video — or text to image on an image model |
first_frame | image to video |
first_frame + last_frame | first & last frame |
reference | image editing (repeatable, up to the model's max_images) |
"content": [
{ "type": "text", "text": "the camera pushes forward slowly" },
{ "type": "image_url",
"role": "first_frame",
"image_url": { "url": "https://… or data:image/png;base64,…" } }
]role accepts first_frame, last_frame and reference. Images may be http(s) URLs or base64 data URIs, up to 30MB after encoding. Supplying last_frame alone is invalid.
reference is for image editing and may be given more than once, up to the max_images the model declares in /v1/models; exceeding it is refused rather than truncated. It cannot be combined with first_frame or last_frame, which describe a different operation.
Query a task
GET /v2/query/video_generation/{task_id}A real response from production, with signature parameters elided:
{
"task": {
"id": "a054377657dc4c1f9130144919128106",
"model": "MiniMax-H3",
"status": "succeeded",
"created_at": 1789451983,
"updated_at": 1789452007,
"task_type": "generation",
"modality": "video",
"content": {
"url": "https://h3.oneclickamd.ai/v1/files/download?exp=…&sig=…",
"type": "video"
},
"resolution": "1344x768",
"duration": 5,
"x_effective_duration": 5.167
}
}Image tasks return the same shape. Three fields differ: modality and content.type are image, and duration is always 1. content.url points at a png and is fetched exactly the same way.
| Field | Notes |
|---|---|
status | See the status table below |
content.url | Present only when succeeded. Signed link, valid 24h, needs no auth header |
resolution | Top level, not inside content. Present only when succeeded |
duration | Echoes the integer you requested |
x_effective_duration | The actual delivered length. Billing follows this value |
x_steps | The denoising steps in force. When a request was out of range this is the clamped value, which is also the one billed |
error | Present only when failed: {type, message} |
create and query are not symmetric: create returns task_id at the root, query nests id inside task. This follows the official spec; assuming symmetry will break.
Status values
| v2 | v1 | Meaning |
|---|---|---|
queued | Queueing | Accepted, waiting for a GPU |
running | Preparing / Processing | Generating |
succeeded | Success | Done, content.url available |
failed | Fail | Failed, credits refunded |
cancelled | Fail | Cancelled. v1 has no such state and collapses it to Fail |
Poll about every 2 seconds. A five-second video usually completes in around 25 seconds; a 1024×1024 image in about 50. The first request at a resolution the backend has not seen takes noticeably longer — it compiles convolution kernels on the spot. That path is slow, not failing.
Errors
v2 error body:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "content must be a non-empty array",
"http_code": "400"
},
"request_id": "req_14cd42bec964453e95e53292c9c67ddb"
}Include request_id when reporting a problem. The full set of codes and types:
| HTTP | error.type | Meaning and handling |
|---|---|---|
| 400 | invalid_request_error | Bad parameters. Retrying won't help; fix the request |
| 400 | content_policy_violation | The prompt failed moderation |
| 401 | authentication_error | Key missing, wrong, or revoked |
| 402 | insufficient_credits | Not enough credits. The message states how many are needed and available |
| 403 | permission_error | Authenticated, but not allowed |
| 404 | not_found_error | Task does not exist, or is not yours. Both return the same 404 |
| 409 | quota_exceeded | Quota is full, e.g. 5 queued tasks. Waiting won't help; free a slot first |
| 429 | rate_limit_error | Rate limited. Back off and retry |
| 500 | api_error | Server-side error. Safe to retry |
During a deploy the gateway is unavailable for 10–30 seconds (single replica, Recreate strategy) and returns 502/503 rather than the errors above. Clients should retry rather than treat these as failures.
Duration and the frame lattice
Frame count must land on a 17n+5 lattice at a fixed 24 fps. Requested values snap up to the nearest position:
ask 4s → 107 frames → 4.458s
ask 5s → 124 frames → 5.167s
ask 8s → 192 frames → 8.000s ← the only whole second in range
ask 15s → 345 frames → 14.375sduration echoes your request; x_effective_duration is the real length, and billing follows it. The full lattice is available from the duration field of /v1/models.
Downloading media
content.url is a signed link valid for 24 hours and needs no Authorization header, which is what lets browsers, ffmpeg and ComfyUI fetch it directly. Equally, anyone holding the link can open it. The URL is stable while valid, so it is safe to use as a <video> src.
Public gallery
GET /v1/gallery?limit=24&before=<published_at>No authentication required. Returns published and approved work, newest first. Each item has task_id, prompt, author (nickname), model, task_kind, modality, resolution, url and thumb_url; video items additionally carry effective_duration. Never a user identifier. Page with next_before from the response; null means the end.
Filtering by video or image
GET /v1/tasks?modality=image
GET /v1/gallery?modality=videoBoth list endpoints accept modality, whose only values are video and image. Omit it to get everything. This is exactly what separates the Video and Image tabs in the interface.
Filtering happens before paging, so limit=20&modality=image returns 20 images — not whatever is left after 20 mixed rows are filtered down. next_before is computed over the filtered result, so paging works as usual.
Any other value is an invalid-parameter error (under the v1 error convention described below), not a silent fall back to returning everything — so a typo surfaces immediately instead of looking like it worked.
The split is by task kind: t2i counts as an image, everything else as video. The modality field on a task object already carries that answer, so you never have to derive it.
Pagination
List endpoints use cursor pagination rather than offset: pass the next_before from the previous response as before on the next request. A null next_before means there is nothing more.
Repeat modality on every page request — it is not remembered by the cursor.
v1 compatibility
v1 exists for current clients such as ComfyUI's MiniMax nodes. It matches the real MiniMax behaviour: it always returns HTTP 200, with errors carried in base_resp.
{ "base_resp": { "status_code": 2013, "status_msg": "prompt is required" } }| status_code | Meaning |
|---|---|
0 | Success |
1002 | Rate limit or quota |
1004 | Authentication failed |
1013 | Internal error |
2013 | Invalid parameters |
v1 clients must check base_resp.status_code. Looking only at the HTTP status will treat every failure as a success.
Limits
| Prompt | 8,000 characters |
|---|---|
| Duration | 4–15 seconds |
| Input image | 30MB after encoding |
| Concurrency | 5 queued tasks per user |
| API key | Up to 5 active |
| Retention | 7 days; download links 24 hours |