API One Doc

Grok Video Generation

Create fixed 15-second grok-1.5-video reference-image videos: request contract, image URLs, polling, errors, and a reusable JavaScript example.

Grok Video Generation Developer Guide

This page is the only public integration contract for grok-1.5-video in APIOne. It is intentionally self-contained so it can be supplied directly to an AI coding tool or implementation team.

Call only the APIOne endpoints documented here and send the public model name exactly as grok-1.5-video. Do not replace it with aliases or call any other service directly.

Integration summary

ItemFixed rule
Base URLhttps://apione.org
Create taskPOST /xai/v1/videos/generations
Poll taskGET /xai/v1/videos/{request_id}
AuthenticationAuthorization: Bearer <APIOne API Key>
Modelgrok-1.5-video
Duration15 seconds; send duration: 15
InputPublic image URLs in JSON; do not use multipart/form-data
Image countOne image, or two to seven ordered reference images
Text-to-videoAt least one reference image is currently required

Create and manage the API key in APIOne. Store it only in a server-side environment variable or a secure secret store—never in a browser bundle, mobile app, repository, or log.

Create a video

POST https://apione.org/xai/v1/videos/generations
Authorization: Bearer <APIOne API Key>
Content-Type: application/json

Request fields

FieldTypeRequiredAllowed value / limitDescription
modelstringYesExactly grok-1.5-videoThe public model name.
promptstringYesNon-empty stringDescribe the scene, movement, camera, timing, and style.
imageobjectOne of image or reference_images{ "url": "http(s)://..." }Use for a single reference image.
reference_imagesarrayOne of image or reference_images2–7 itemsUse for multiple images; every item is { "url": "http(s)://..." }.
durationintegerYesExactly 15Video duration is fixed at 15 seconds.
aspect_ratiostringYes2:3, 3:2, 1:1, 16:9, 9:16Output aspect ratio. The field name must be aspect_ratio.
resolutionstringYes720p, 1080pOutput resolution. Use a lowercase p.

Do not send size, ratio, input_reference, file bytes, Base64/Data URLs, or multipart/form-data to this endpoint. They are not part of this public request format.

Reference-image URLs and ordering

  • Each image must be an http:// or https:// URL that remains publicly retrievable for the duration of the task. HTTPS and non-expiring URLs are recommended for production.
  • Do not use local paths, private-network URLs, browser object URLs, Base64/Data URLs, or URLs that need cookies or interactive sign-in.
  • Send either image or reference_images, never both.
  • In reference_images, array position defines the prompt reference: first image is @img1, second is @img2, through @img7.
  • Refer to images in prompt with the fixed spelling @img1, @img2, and so on.
  • One reference image supports 720p or 1080p. Two to seven reference images support 720p only; a multi-reference request with 1080p returns 400.

Single-image request

curl --request POST 'https://apione.org/xai/v1/videos/generations' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "grok-1.5-video",
    "prompt": "Have the character in @img1 turn slowly as the camera moves smoothly from close-up to medium shot in cinematic natural light.",
    "image": {
      "url": "https://files.example.com/character.png"
    },
    "duration": 15,
    "aspect_ratio": "16:9",
    "resolution": "1080p"
  }'

Multiple-reference request

Array order determines the relationship of @img1, @img2, and @img3. Multiple references must use 720p.

curl --request POST 'https://apione.org/xai/v1/videos/generations' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "grok-1.5-video",
    "prompt": "Gradually transform and shatter @img1 into @img2, then transition smoothly into @img3 while keeping the subject centered.",
    "reference_images": [
      { "url": "https://files.example.com/one.png" },
      { "url": "https://files.example.com/two.png" },
      { "url": "https://files.example.com/three.png" }
    ],
    "duration": 15,
    "aspect_ratio": "16:9",
    "resolution": "720p"
  }'

Create response

A successful create request returns HTTP 200:

{
  "request_id": "task_01KABCDEF1234567890XYZ"
}

request_id is an opaque APIOne task identifier. Store it exactly as returned alongside your own user and business-order records. Do not try to parse it or substitute it with another task ID.

Poll a video task

GET https://apione.org/xai/v1/videos/{request_id}
Authorization: Bearer <APIOne API Key>

Poll responses

Queued or in progress:

{
  "request_id": "task_01KABCDEF1234567890XYZ",
  "status": "pending",
  "model": "grok-1.5-video"
}

Succeeded:

{
  "request_id": "task_01KABCDEF1234567890XYZ",
  "status": "done",
  "model": "grok-1.5-video",
  "video": {
    "url": "https://files.example.com/videos/result.mp4"
  }
}

Failed:

{
  "request_id": "task_01KABCDEF1234567890XYZ",
  "status": "failed",
  "model": "grok-1.5-video",
  "error": {
    "code": "generation_failed",
    "message": "Video generation failed"
  }
}
statusClient action
pendingThe task is unfinished; keep polling.
doneRead and persist video.url, then stop polling.
failedStop polling and handle error.message.

GET /xai/v1/videos/generations/{request_id} is a compatibility polling path. New integrations should use the shorter canonical path above.

After a successful create request, do not submit the task again. Poll with its request_id instead:

  1. Wait 2 seconds before the first poll, then use exponential delays of 2, 4, and 8 seconds.
  2. Cap the interval at 8–10 seconds to avoid unnecessary traffic.
  3. Stop immediately on done or failed.
  4. Set an application-level timeout, such as 10 minutes. A client timeout only stops waiting; it does not necessarily mean the task failed.

Optionally, use the normalized async endpoint GET /v1/api/result?id={request_id}. It reports standard states such as running, succeeded, failed, and violation. If you use the dedicated endpoint above, do not poll both endpoints for the same task.

Reusable JavaScript implementation

The following implementation can be used in server-side Node.js, a Next.js route handler, Cloudflare Workers, or a similar backend environment. Browser clients must call your backend rather than expose the API key.

const APIONE_BASE_URL = 'https://apione.org';
const GROK_VIDEO_MODEL = 'grok-1.5-video';

function validateCreateInput({ prompt, imageUrls, aspectRatio, resolution }) {
  if (typeof prompt !== 'string' || !prompt.trim()) {
    throw new Error('prompt must be a non-empty string');
  }
  if (!Array.isArray(imageUrls) || imageUrls.length < 1 || imageUrls.length > 7) {
    throw new Error('imageUrls must contain 1 to 7 public image URLs');
  }
  if (!['2:3', '3:2', '1:1', '16:9', '9:16'].includes(aspectRatio)) {
    throw new Error('unsupported aspectRatio');
  }
  if (!['720p', '1080p'].includes(resolution)) {
    throw new Error('resolution must be 720p or 1080p');
  }
  if (imageUrls.length > 1 && resolution !== '720p') {
    throw new Error('multiple reference images support 720p only');
  }
  for (const value of imageUrls) {
    const url = new URL(value);
    if (!['http:', 'https:'].includes(url.protocol)) {
      throw new Error('every image URL must use HTTP(S)');
    }
  }
}

async function readJson(response) {
  const body = await response.json().catch(() => null);
  if (!response.ok) {
    const message = body?.message || body?.error?.message || `HTTP ${response.status}`;
    const error = new Error(message);
    error.status = response.status;
    error.code = body?.code || body?.error?.code;
    throw error;
  }
  return body;
}

export async function createGrokVideo({ apiKey, prompt, imageUrls, aspectRatio, resolution }) {
  validateCreateInput({ prompt, imageUrls, aspectRatio, resolution });
  const imageFields = imageUrls.length === 1
    ? { image: { url: imageUrls[0] } }
    : { reference_images: imageUrls.map((url) => ({ url })) };

  const response = await fetch(`${APIONE_BASE_URL}/xai/v1/videos/generations`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: GROK_VIDEO_MODEL,
      prompt,
      ...imageFields,
      duration: 15,
      aspect_ratio: aspectRatio,
      resolution,
    }),
  });
  const result = await readJson(response);
  if (!result?.request_id) throw new Error('APIOne did not return request_id');
  return result.request_id;
}

export async function waitForGrokVideo({ apiKey, requestId, timeoutMs = 10 * 60 * 1000 }) {
  const startedAt = Date.now();
  let delayMs = 2_000;
  while (Date.now() - startedAt < timeoutMs) {
    await new Promise((resolve) => setTimeout(resolve, delayMs));
    const response = await fetch(
      `${APIONE_BASE_URL}/xai/v1/videos/${encodeURIComponent(requestId)}`,
      { headers: { Authorization: `Bearer ${apiKey}` } },
    );
    const task = await readJson(response);
    if (task.status === 'done') return task.video.url;
    if (task.status === 'failed') throw new Error(task.error?.message || 'video generation failed');
    if (task.status !== 'pending') throw new Error(`unknown task status: ${task.status}`);
    delayMs = Math.min(delayMs * 2, 8_000);
  }
  throw new Error('timed out waiting for the video task');
}

Errors and retry rules

Typical error shape:

{
  "code": "invalid_request",
  "message": "A required request field is missing",
  "data": null
}
SituationTypical HTTP statusCorrect handling
Invalid fields, image URL, image count, or resolution400Fix the request; do not retry it unchanged.
Both image and reference_images sent400Rebuild the request with exactly one input form.
Multiple images with 1080p400Change to 720p or use only one reference image.
Missing or invalid API key401Fix the server-side key configuration.
Insufficient quota402Add quota or use a key with available quota.
Rate limited429Retry with exponential backoff and limit concurrency.
Temporary service failure5xxRetry after a short delay; if request_id was returned, poll it instead of creating a duplicate task.

Do not expose API keys, authorization headers, full task requests, private image URLs, or any server-side diagnostic data in end-user errors or client-visible logs.

AI implementation checklist

  • Use only grok-1.5-video.
  • Submit JSON only to POST /xai/v1/videos/generations; poll only through GET /xai/v1/videos/{request_id}.
  • Send numeric duration: 15; use aspect_ratio, not ratio or size.
  • Supply at least one HTTP(S) image URL: use image.url for one image, or ordered reference_images[].url for two to seven images.
  • Use resolution: "720p" for multiple images; one image may use 720p or 1080p.
  • Refer to images in prompt order with @img1 through @img7.
  • Store and poll only APIOne's request_id; read the output from video.url when complete.
  • Keep the API key server-side at all times.

On this page