High-quality video generation by xAI, with natural, fluid motion. It runs on the same unified video endpoint as everything else on apimodels.app: one POST creates the task, then you poll that same endpoint for the result — identical to VEO, Kling and Seedance, so switching models is a one-string change. Two public model names: grok-video-3 is priced per second at $0.02/s for 6 / 10 / 15-second output, and grok-video-3-10s is a flat $0.20 per 10-second clip. Both support image-to-video.
| Model | model | Duration | Price | Notas |
|---|---|---|---|---|
| Grok Video 3 | grok-video-3 | 6 / 10 / 15s | $0.12-$0.30 | Image-to-video, $0.02/s |
| Grok Video 3 (10s) | grok-video-3-10s | 10s | $0.20 | Image-to-video, 10s preset (flat per clip) |
Both names are the same model; only the billing shape differs. Take grok-video-3 when you want 6 or 15 seconds, or want to pay for exactly the seconds you use; take grok-video-3-10s when a standard 10-second clip at a flat, predictable price is all you need — at the 10-second mark the two cost the same ($0.20).
POST /api/v1/video/generations — async: create, then poll the same endpoint for the result.
# Step 1: Create task
curl -X POST https://apimodels.app/api/v1/video/generations \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-video-3",
"prompt": "A cat playing piano in a jazz club, cinematic lighting",
"aspect_ratio": "16:9"
}'
# Step 2: Poll status
curl "https://apimodels.app/api/v1/video/generations?task_id=TASK_ID" \
-H "Authorization: Bearer YOUR_API_KEY"| Field | Required | Type | Description |
|---|---|---|---|
| model | Yes | string | grok-video-3 / grok-video-3-10s |
| prompt | Yes | string | Text description of the video to generate |
| aspect_ratio | No | string | "16:9" (default), "1:1", "9:16", "2:3", "3:2" |
| size | No | string | "720P" (default), "1080P" |
| callback_url | No | string | URL del webhook que se invoca cuando la tarea finaliza |
The create call returns data.taskId right away and the video renders in the background. GET the same endpoint with that task_id and read data.state: pending means still running, completed puts the video URL in data.resultUrls[0], and failed puts the reason in data.failMsg. To skip polling entirely, pass callback_url and we POST you when the task finishes.
Yes. On apimodels.app you POST to /api/v1/video/generations with model "grok-video-3" (or "grok-video-3-10s"), a prompt and an optional aspect_ratio, then poll the same endpoint with the returned task_id until data.state is "completed" — data.resultUrls[0] is the video. It is the same request shape as VEO, Kling and Seedance here, so switching models is a one-string change, and one API key covers all of them.
grok-video-3 is billed per second at $0.02/s, so a 6-second clip is $0.12, 10 seconds is $0.20 and 15 seconds is $0.30. The separate grok-video-3-10s preset is a flat $0.20 per 10-second clip. Failed tasks are not billed — you are only charged on success.
Same model, different billing shape. grok-video-3 gives you 6, 10 or 15-second output billed per second at $0.02/s ($0.12-$0.30). grok-video-3-10s is fixed at 10 seconds for a flat $0.20 per clip, which is easier to budget for batch jobs. At the 10-second mark the two cost exactly the same, so pick the preset only if you want a fixed length at a fixed price.
Yes — both grok-video-3 and grok-video-3-10s support image-to-video as well as plain text-to-video, through the same /api/v1/video/generations endpoint. You can try the image workflow directly on the model pages at apimodels.app/models/grok-video-3 and /models/grok-video-3-10s.
aspect_ratio accepts "16:9" (the default), "1:1", "9:16", "2:3" and "3:2", so landscape, portrait and square all come from one endpoint — no model switching for social formats. A 10-second clip typically comes back in about 60 seconds and shorter ones in around 30, so poll every 5-10 seconds, or pass callback_url and let us POST you when the task finishes.
Result videos are hosted for 7 days and then deleted automatically, so download or re-host anything you need to keep. The URL comes back in data.resultUrls[0] once data.state is "completed"; if the task fails, data.failMsg carries the reason and nothing is charged.