AI video generators, reviewed by what their APIs reject
Most AI video generator reviews score the output: how the faces hold up, whether the physics look right, which one nails a dolly zoom. That is useful for picking a tool to open in a browser. It is close to useless if you are going to call one from code, because output quality changes with every checkpoint, while the parameter contract is what your integration has to live with for the next year.
So here is the other review. Six video models, judged on what their APIs refuse to accept, where the refusal is silent, and how much of your client survives swapping one model for another. Everything below comes from a request surface I maintain.
One framing note. I am not affiliated with any of these labs. I reach these models through third-party channels, so channel-level caps can differ from whatever a first-party API exposes, and none of this is official documentation.
The same parameter can have three contracts inside one model
MiniMax H3 takes an aspect_ratio. What that field means depends entirely on which mode you are in.
| Mode | aspect_ratio |
|---|---|
| Text to video | Required, and adaptive is rejected |
| Image to video | Forbidden. Orientation comes from the source image |
| Reference to video | Optional, defaults to adaptive |
The middle row is the interesting one. The field is not ignored there, and it is not optional. Sending a valid enum value, one this same model accepts in another mode, fails the request. A generic client that always sets aspect_ratio from user config works in two modes out of three, and the failure surfaces as a validation error about a field the docs told you to send.
Seedance 2.5 has the same shape with different edges. It accepts seven ratios plus adaptive, but first-plus-last-frame requests have to leave the size at adaptive, because upstream rejects any other value at submit time. Same model, same field, and whether it is settable depends on which image mode you chose two fields earlier. Mode is not a filter over one schema. It is several schemas that happen to share field names.
Documented as optional, enforced as required
Seedance 2.5 requires a prompt on every request, minimum three characters, image-to-video included. The documentation for the channel describes the prompt as optional when reference material is supplied. The endpoint disagrees and returns an error.
The version history makes this worse for anyone upgrading. The 2.0 family let you submit an image with no prompt and take whatever motion the model inferred. Point the same client at 2.5 and every bare image-to-video call starts failing. Nothing in the model name signals that the required fields changed.
"Optional" in a vendor doc is a hypothesis, not a fact. The cheap test is to fire one deliberately minimal request per mode during integration and record what comes back. It takes ten minutes, and the result is the only version of the schema you can trust.
The channel decides the parameter surface, not the model
Veo 3.1 is one model. Reached through three different resale channels, it is three different APIs.
| Channel A | Channel B | Channel C | |
|---|---|---|---|
| Duration | Fixed 8s | Fixed 8s | Selectable |
| Resolution control | No | Yes | Yes |
| Negative prompt | No | No | Yes |
| Seed | Yes | No | Yes |
Nothing here is a quality difference. It is the same weights. But an integration written against the third column, using seed for near-reproducible re-rolls and a negative prompt to suppress a recurring artifact, loses both the moment someone flips a routing env var to the second column. The requests still succeed. The outputs just stop respecting parameters you are still sending.
The adapter layer you write to paper over those differences tends to widen the silence rather than close it. Mine did. Normalizing per-channel enums looks harmless:
aspect_ratio = request.get("aspect_ratio", "16:9")
if aspect_ratio not in VALID_ASPECT_RATIOS:
aspect_ratio = "16:9"
That clamp stops the channel erroring, and it means a user who asks for 21:9 where only two ratios exist gets a successful 16:9 render, billed normally, with nothing anywhere saying they were overruled. Parameters a channel never implemented are not read at all, so they vanish a layer earlier. Decide deliberately whether an unsupported value should clamp or fail, and tell the caller which one happened.
The same config carried a fourth channel that was mapped, wired, and non-functional: the routing layer rejects it for this model with an invalid-tier error on every call. A provider being present in your config is not evidence that it is reachable. So model_name is not a sufficient key for capability. (model_name, channel) is.
Some models have no mode parameter at all
HappyHorse 1.0 exposes a single model id and infers the mode from which media fields you populated, in priority order: a video URL wins, then a first-frame image, then a list of reference images, then prompt-only.
This is elegant until you leave a field set. A client that keeps video_url from the previous request while the user is now trying a text-to-video generation does not get an error. It gets a video edit. The request is well formed, the mode is just not the one anyone intended, and the bill lands in the edit tier. Anywhere the API derives intent from field presence rather than an explicit mode enum, clear your media fields on mode switch. Explicitly, not by trusting your form state.
Constraints that no schema can express
Three real ones, all of which have to live in application code because a flat parameter list cannot hold them:
- MiniMax H3 accepts audio references, but not alone. At least one image or video reference has to accompany them. That is a cross-field rule, not a field rule.
- The same model's wire format allows a last-frame-only image-to-video request. Expressing "either frame, at least one" in a schema of independent fields is not possible, so the form requires a first frame and quietly gives up some capability.
- Grok Imagine Video 1.5 is image-to-video only, and its audio is generated in the same pass with no toggle. There is no audio parameter to expose, so "does this model support audio" and "does this model have an audio parameter" have different answers.
Each of these is a place where a schema-driven form or a generated client rejects valid requests, or accepts invalid ones.
Billing is part of the contract
No numbers here, since rates move and differ per channel. The shapes are the part a per-second price will not tell you:
- Attaching a reference video can make the bill count input seconds on top of output seconds, with a floor and a ceiling. A ten-second reference clip is not free context. Trim references to the segment that demonstrates the thing you want.
- Auto-duration, where the model chooses the length, reserves at the maximum and settles afterward. If your app quotes the user before generating, auto-duration and upfront quoting are in conflict, and the model tends to pick short.
- Reference images past a free allowance can bill individually, so "up to 9 images" and "9 images at no extra cost" are different sentences.
What I check before integrating
The review criteria, in the order that has saved me the most time:
- Fire one minimal request per mode and record what comes back. That is the real schema.
- Diff the required fields across modes, not just across models.
- Ask which fields are forbidden, not just which are required. Forbidden fields are the ones docs
Comments
No comments yet. Start the discussion.