Grok CLI Manual
Video Generation
Grok Build and REST share xai_api_base_url. For manual REST calls, save the request_id returned by the Router immediately after creation.
Configure the video endpoint
Video and image tools share xai_api_base_url:
[endpoints]
models_base_url = "https://api.xairouter.com"
xai_api_base_url = "https://api.xairouter.com"
[auth]
preferred_method = "api_key"Set both fields to the XAI Router main API origin without /v1. Grok Build appends /videos/... to xai_api_base_url; direct REST calls use the standard /v1/videos/... paths. Model, image, and video requests use the same XAI Router user Key.
Generate video in Grok Build
The current version supports:
/imagine-video A crystal-powered spacecraft rising from a Martian canyon, cinematic wide shot, 16:9/imagine-video first creates a starting frame with image_gen, then calls image_to_video; it is not a direct text-to-video tool. On completion, Grok saves the file under the current session's videos/<number>.mp4 path and links it in the reply.
To animate an existing image, request the tool explicitly:
Call image_to_video on /absolute/path/to/first-frame.jpg. Use a slow camera push-in with wind moving the leaves in the background, 6 seconds, 720p.Use reference_to_video when multiple content or style references are required:
Call reference_to_video with /absolute/path/to/subject.jpg and /absolute/path/to/style.jpg to create a cinematic 16:9, 6-second, 720p shot.The current Grok Build tools are more constrained than direct API calls:
| Item | Current Grok Build constraint |
|---|---|
| Workflow | One starting image, or video generation from 2–7 reference images |
| Duration | 6 or 10 seconds; default 6 |
| Resolution | 480p or 720p; default 480p |
| Reference source | Absolute local path, HTTPS URL, or base64 data URL |
| Aspect ratio | Reference mode supports 1:1, 16:9, 9:16, 3:2, and 2:3 |
image_to_video uses the 1.5 quality model, while reference_to_video uses the base video model. The tool and Router select the model automatically; there is no tool argument for changing it. Grok Build manages the request_id, polls every five seconds, and stops waiting after five minutes. The ID-preservation guidance below applies to manual REST calls.
Local images are converted to base64 inside the request body. Prefer trusted HTTPS URLs for multiple images to reduce upload size and memory use.
Call the Videos API directly
For direct calls, prefer the stable grok-imagine-video-1.5 model name. First confirm that the Router publishes and permits it for the current account:
curl -fsS https://api.xairouter.com/v1/models \
-H 'Authorization: Bearer YOUR_XAI_ROUTER_KEY' \
| jq -r '.data[].id' | grep '^grok-imagine-video'The model list reflects the Router catalog and access rules; it does not probe the selected upstream account's Imagine entitlement in real time. Actual permission and quota are determined when the request runs.
| Model | Scope |
|---|---|
grok-imagine-video-1.5 | Recommended; text-to-video and image-to-video support 480p, 720p, and 1080p |
grok-imagine-video | Compatibility model; supports 480p and 720p |
The REST API accepts integer durations from 1 to 15 seconds. Common ratios include 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, and 2:3. Reference-to-video is capped at 720p. The current Router video path exposes creation and status polling, not the official edit or extension endpoints.
This complete text-to-video script saves the creation response and request_id immediately, polls until completion, and downloads the temporary video URL:
set -euo pipefail
BASE_URL="https://api.xairouter.com"
ROUTER_API_KEY="YOUR_XAI_ROUTER_KEY"
JOB_FILE="grok-video-job.json"
STATUS_FILE="grok-video-status.json"
curl -fsS "$BASE_URL/v1/videos/generations" \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "grok-imagine-video-1.5",
"prompt": "A crystal-powered spacecraft rises from a Martian canyon, cinematic wide shot",
"duration": 6,
"aspect_ratio": "16:9",
"resolution": "720p"
}' > "$JOB_FILE"
REQUEST_ID="$(jq -er '.request_id | strings | select(startswith("vjob_"))' "$JOB_FILE")"
printf 'request_id=%s\n' "$REQUEST_ID"
MAX_POLLS=120
VIDEO_URL=""
for ((ATTEMPT = 1; ATTEMPT <= MAX_POLLS; ATTEMPT++)); do
if ! curl -fsS --retry 3 --retry-delay 2 --retry-max-time 20 --retry-connrefused \
"$BASE_URL/v1/videos/$REQUEST_ID" \
-H "Authorization: Bearer $ROUTER_API_KEY" > "$STATUS_FILE"; then
printf 'poll failed; request_id remains saved in %s\n' "$JOB_FILE" >&2
exit 1
fi
STATUS="$(jq -r '.status // empty' "$STATUS_FILE")"
case "$STATUS" in
done)
VIDEO_URL="$(jq -er '.video.url' "$STATUS_FILE")"
break
;;
failed|expired)
jq . "$STATUS_FILE" >&2
exit 1
;;
pending)
sleep 5
;;
*)
jq . "$STATUS_FILE" >&2
exit 1
;;
esac
done
if [[ -z "$VIDEO_URL" ]]; then
printf 'poll timed out; request_id remains saved in %s\n' "$JOB_FILE" >&2
exit 1
fi
curl -fL --retry 3 --retry-delay 2 "$VIDEO_URL" --output grok-video.mp4For image-to-video, add this field to the creation request:
"image": {"url": "https://example.com/first-frame.jpg"}For multiple references, use:
"reference_images": [
{"url": "https://example.com/subject.jpg"},
{"url": "https://example.com/style.jpg"}
]image and reference_images select different modes and must not be combined in one request.
Preserve request_id correctly
After a successful creation, XAI Router returns a public job ID beginning with vjob_. It pins subsequent polling to the same upstream account that created the task. Treat it as an opaque string and pass it unchanged to GET /v1/videos/{request_id} with a Key for the same Router user.
There is currently no video-job list, history search, or alternative recovery endpoint. If the request_id is forgotten or lost, polling cannot be recovered, so save the complete creation response first as the script does. The final video.url is also temporary; download the asset promptly if it must be retained.
Creation is non-idempotent. Do not blindly replay a POST after a timeout or broken connection: the upstream may already have created and billed the job. The example polls for about ten minutes at most and retries only the safe status GET a limited number of times. HTTP 202 and pending both mean the job is still running.
Billing behavior
Query the current account's final video prices with its user Key:
curl -fsS https://api.xairouter.com/x-pricing \
-H 'Authorization: Bearer YOUR_XAI_ROUTER_KEY' \
| jq '.data[] | select(.category == "VideoPricing") | {id, unit, final}'Once creation returns 2xx, the Router charges immediately from the submitted duration, resolution, and number of input images. Polling is not charged again. If duration or resolution is omitted, billing defaults to 6 seconds and 480p. A later failed or expired result does not trigger an automatic refund or reconciliation, so verify the request fields and current /x-pricing before submission.
By default, /imagine-video calls image_gen once to create the starting frame and then submits one video job, so the total includes both the image-generation charge and the video charge. Calling image_to_video with an existing image avoids that starting-frame generation charge. Multi-shot workflows charge each shot separately.
Troubleshooting
/imagine-videois unavailable: update Grok Build and confirm that environment flags, remote policy, or a tool denylist has not disabled video tools.- The request reaches xAI and rejects the Key: check
xai_api_base_url, and make sureXAI_API_KEYorGROK_CODE_XAI_API_KEYis not overriding the Router Key. 400or model unavailable: prefer the stable model name for direct API calls and first confirm that it is published byGET /v1/models; the list does not guarantee live upstream entitlement.403or429: check the upstream account's Imagine permission, quota, and rate limit.- Polling returns
503job account unavailable: the exact upstream Key that created the task may have been deleted or disabled. The Router will not switch the job to another account. - Polling returns
400 invalid video request_id: the upstream Key may have been rotated or its Provider/Config changed after creation, invalidating the signature. - A Resources allowlist is enabled: permit
/v1/videosfor standard API clients and/videosfor Grok Build. - The request body is too large: local and base64 images expand in transit. The Router's default request-body limit is 200 MiB; prefer HTTPS URLs.
See the xAI video generation guide, Grok Imagine Video 1.5 model page, and Image-to-Video guide for current model capabilities and parameters.