Video generation API
One POST request with the same key as chat: a scene description in, a link to an mp4 out. Parameters, examples in three languages and the billing rules are collected here.
Endpoints and authentication
Video lives on the OpenAI-compatible entry point and uses the same key as text models: only the path changes. The Anthropic entry point does not generate video.
| Method | Path | Purpose |
|---|---|---|
| POST | https://api.tokenator.top/v1/videos/generations | Generate a clip from a text prompt. The same handler answers /v1/videos. |
| GET | /v1/videos/{id}?model=… | The status of an upstream async job, if you were handed its identifier. |
| GET | /v1/videos/models | The catalog of video models available to this key, together with their parameters. |
The key goes in Authorization: Bearer sk-your-tokenator-key. There is no separate video key — generations are drawn from the same key as tokens.
Your first request
curl https://api.tokenator.top/v1/videos/generations \ -H "Authorization: Bearer sk-your-tokenator-key" \ -H "Content-Type: application/json" \ -d '{ "model": "video-model-id", "prompt": "a neon city in the rain, slow camera fly-through", "duration": 6, "resolution": "720p", "aspect_ratio": "16:9" }'
The answer arrives once the clip is ready and looks like any other generation response: a data array of links.
{
"created": 1755600000,
"data": [
{ "url": "https://api.tokenator.top/static/v/6f2c1a9b.mp4" }
]
}The link points at a file rehosted by the service — the provider's temporary URLs never reach the client. When a model returns the video inline, the item carries b64_json with the file itself instead of url.
Which models do video
No video model is enabled in the catalog right now. The live list is always returned by /v1/videos/models, and on the site it lives in the catalog.
The API returns the same list — with durations, resolutions, aspect ratios and defaults. That is safer than hard-coding parameters: the list changes together with the catalog.
curl https://api.tokenator.top/v1/videos/models \ -H "Authorization: Bearer sk-your-tokenator-key"
{
"object": "list",
"data": [
{
"id": "video-model-id",
"object": "video_model",
"durations": [4, 6, 8],
"resolutions": ["480p", "720p", "1080p"],
"aspect_ratios": ["16:9", "9:16", "1:1"],
"audio": true,
"image_input": true,
"default_duration": 4,
"default_resolution": "720p",
"default_aspect_ratio": "16:9"
}
]
}Request parameters
| Field | Type | What it does |
|---|---|---|
model | string | The API ID of a video model from the catalog. When omitted, the first enabled video model is used — better to pass it explicitly. |
prompt | string, required | The scene description. An empty string is refused with a 400. |
n | integer | How many clips to generate in one request: 1 to 4. Anything above 4 is clamped to 4. |
duration | integer, seconds | Clip length. seconds and duration_seconds are accepted too. The hard ceiling is 60 seconds; the exact list of values comes from the model. |
resolution | string | For example 720p. Synonyms are normalised: sd → 480p, hd → 720p, 1k and fhd → 1080p. |
aspect_ratio | string | The aspect ratio, for example 16:9. The x spelling (16x9) is understood as well. |
size | string | A frame size such as 1280x720. When aspect_ratio is absent, the ratio is derived from it. |
generate_audio | boolean | Ask the model to render sound. Only models that declare audio accept it. |
seed | integer | The generation seed — with the same value the result is reproducible as far as the model allows. |
frame_images | array | Starting frames, to animate an existing image. |
input_references | array | Style or character references. Together with frame_images — at most four images per request. |
Fields you leave out are filled from the model's defaults, and values outside the declared list are refused before the provider is contacted — a rejected attempt costs no generations. The callback_url, webhook_url and provider fields are stripped and never forwarded upstream: callbacks would bypass your key.
How long it takes and what happens inside
A render takes from tens of seconds to a few minutes. The request is synchronous: the connection is held until the clip is ready, and to keep intermediate proxies from closing it on silence the service pads the response body with keep-alive whitespace. The final JSON arrives as the last chunk — an ordinary parser reads it as-is.
When the provider answers with an async job, the proxy polls it and returns the finished clip — you do not need your own polling loop. The total wait is capped at 15 min; after that you get a 504 and the claimed generations are returned to the key.
The practical consequence: raise your HTTP client timeout to 15 min and do not retry on timeout — a repeat request starts a second render.
curl "https://api.tokenator.top/v1/videos/vid_123?model=video-model-id" \ -H "Authorization: Bearer sk-your-tokenator-key"
The model parameter matters here: it selects the provider to ask for the status. Without it the request goes to the first enabled video model.
Starting frames and references
Models that declare image input can animate an existing frame. Images go in frame_images, style or character references in input_references; at most four in total per request. If the model declares no image input, the request is refused with a 400 — before any generation is claimed.
{
"model": "video-model-id",
"prompt": "the camera slowly pushes in, wind moves the leaves",
"duration": 4,
"frame_images": ["https://example.com/frame.jpg"]
}SDKs and ready-made examples
The video endpoint is not part of the typed surface of the OpenAI SDKs, so the convenient way to call it is a raw request. The key and the base URL stay the same as for chat — no separate client needed.
from openai import OpenAI client = OpenAI( api_key="sk-your-tokenator-key", base_url="https://api.tokenator.top/v1", timeout=900, ) result = client.post( "/videos/generations", body={ "model": "video-model-id", "prompt": "a neon city in the rain", "duration": 6, "resolution": "720p", }, cast_to=dict, ) print(result["data"][0]["url"])
import requests response = requests.post( "https://api.tokenator.top/v1/videos/generations", headers={"Authorization": "Bearer sk-your-tokenator-key"}, json={ "model": "video-model-id", "prompt": "a neon city in the rain", "duration": 6, "resolution": "720p", }, timeout=900, ) response.raise_for_status() print(response.json()["data"][0]["url"])
const response = await fetch("https://api.tokenator.top/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer sk-your-tokenator-key", "Content-Type": "application/json", }, body: JSON.stringify({ model: "video-model-id", prompt: "a neon city in the rain", duration: 6, resolution: "720p", }), signal: AbortSignal.timeout(900_000), }) const result = await response.json() console.log(result.data[0].url)
Ready-made snippets with your own key and address are in the key dashboard, next to the chat ones.
How video is billed
Video does not spend tokens. A key carries a separate video-generation counter, and one generation is one clip at the base resolution and the base duration. Heavier parameters cost proportionally more: the resolution multiplier is set by the operator (say 480p — 1×, 720p — 2×, 1080p — 4×), and duration scales against the base one. The final charge is clips × model multiplier × resolution multiplier × duration multiplier, rounded up.
Generations are claimed before the provider is contacted and returned if no clip arrives: a failed render costs nothing. Video bundles are sold separately from tokens; a key with token_limit: -1 is a generation-only key with no access to text models.
curl https://api.tokenator.top/v1/tokens \ -H "Authorization: Bearer sk-your-tokenator-key"
{
"name": "my-key",
"limit": 1000000,
"used": 240000,
"remaining": 760000,
"image_limit": 0,
"image_used": 0,
"image_remaining": 0,
"video_limit": 20,
"video_used": 3,
"video_remaining": 17
}Limits
- Up to 4 clips per request (
n); anything above is clamped to 4. - A clip is at most 60 seconds long, and never longer than the model declares.
- At most four input images per request (
frame_imagesandinput_referencescombined). - Concurrent renders per key: 1. A request beyond that is not queued — it gets a
429with abusy_for_secondsfield. - The total wait for one request is capped at 15 min.
Errors
| Symptom | Cause | Fix |
|---|---|---|
400 prompt required | The body carries no scene description, or is not JSON at all. | Check Content-Type: application/json and a non-empty prompt. |
400 about duration, resolution or aspect ratio | The value is not in the list the model declares. | The error message lists the allowed values; /v1/videos/models returns the same list. |
400 does not generate video | The request named a text or image model. | Take a video model ID from the catalog. |
429 with a video_gen_limit | The key has run out of video generations. | Top up a video bundle in your account; the balance is visible in /v1/tokens. |
429 with a video_concurrent_limit | A render is already running on this key: parallel renders are limited. | The busy_for_seconds field shows how long the current render has been going. Queue requests instead of firing them in parallel. |
504 | The model did not finish rendering in the allotted time. | Try a shorter clip or a lower resolution. Claimed generations are refunded. |
502 Request error | An error on the provider side. Its text is not passed through to the client. | Retry — Tokenator fails over to the next provider on its own. If it persists, contact support. |
Trying it without code
The key dashboard has a Studio with an Images / Video switch: duration, resolution and aspect ratio are picked with buttons and finished clips land in a gallery. It is the same endpoint and the same generation counter — a convenient way to try a model before writing an integration.
FAQ
Do I need a separate key for video?
No. The same key as for chat works; only the request path changes. What is bought separately is the bundle of generations.
Can I generate video through the Anthropic format?
No. Video lives only on the OpenAI-compatible entry point — /v1/videos/generations. For chat the two formats remain interchangeable.
How do I learn which durations and resolutions a model supports?
Ask /v1/videos/models: it returns the durations, resolutions and aspect_ratios lists along with the defaults. The same values are on the model page in the catalog.
Are generations charged when a render fails?
No. Generations are claimed before the request and returned to the key when no clip arrives — a provider error or a timeout costs nothing.
How long does the link to a finished video live?
The file is rehosted by the service and served from our address rather than the provider's temporary link. Download it right away if you need the clip for the long run.
Can I run several renders in parallel?
Per key — 1 at a time; further requests get a 429. Several clips in one request are ordered with the n field (up to four).