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:

ItemCurrent Grok Build constraint
WorkflowOne starting image, or video generation from 2–7 reference images
Duration6 or 10 seconds; default 6
Resolution480p or 720p; default 480p
Reference sourceAbsolute local path, HTTPS URL, or base64 data URL
Aspect ratioReference 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.

ModelScope
grok-imagine-video-1.5Recommended; text-to-video and image-to-video support 480p, 720p, and 1080p
grok-imagine-videoCompatibility 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.mp4

For 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-video is 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 sure XAI_API_KEY or GROK_CODE_XAI_API_KEY is not overriding the Router Key.
  • 400 or model unavailable: prefer the stable model name for direct API calls and first confirm that it is published by GET /v1/models; the list does not guarantee live upstream entitlement.
  • 403 or 429: check the upstream account's Imagine permission, quota, and rate limit.
  • Polling returns 503 job 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/videos for standard API clients and /videos for 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.