> ## Documentation Index
> Fetch the complete documentation index at: https://runcrate.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Video Generation

> Generate videos from text prompts using Sora, Veo, Kling, and more.

export const RuncrateStyles = () => {
  if (typeof document !== 'undefined' && !document.getElementById('runcrate-overrides')) {
    const s = document.createElement('style');
    s.id = 'runcrate-overrides';
    s.textContent = `
      /* Match Runcrate's rounding scale (--radius: 0.75rem) */
      .rounded-sm { border-radius: 0.5rem !important; }   /* 8px */
      .rounded-md { border-radius: 0.625rem !important; } /* 10px */
      .rounded-lg { border-radius: 0.75rem !important; }  /* 12px */
      .rounded-l-sm { border-top-left-radius: 0.5rem !important; border-bottom-left-radius: 0.5rem !important; }
      .rounded-r-sm { border-top-right-radius: 0.5rem !important; border-bottom-right-radius: 0.5rem !important; }
      .rounded-l-md { border-top-left-radius: 0.625rem !important; border-bottom-left-radius: 0.625rem !important; }
      .rounded-r-md { border-top-right-radius: 0.625rem !important; border-bottom-right-radius: 0.625rem !important; }
      .rounded-l-lg { border-top-left-radius: 0.75rem !important; border-bottom-left-radius: 0.75rem !important; }
      .rounded-r-lg { border-top-right-radius: 0.75rem !important; border-bottom-right-radius: 0.75rem !important; }

      /* Cards: never pure white in light mode */
      .card { background-color: #fcfcfc !important; border-radius: 0.75rem !important; }
      html.dark .card { background-color: #141414 !important; }

      /* Docs hero box */
      .rc-hero { background-color: #fcfcfc; border: 1px solid #e0e0e0; }
      html.dark .rc-hero { background-color: #141414; border-color: #242424; }
      html.dark .rc-hero h1 { color: #f5f5f5; }

      /* Runcrate scrollbar — thin, transparent track, hide-until-hover thumb */
      ::-webkit-scrollbar { width: 6px; height: 6px; background-color: transparent; }
      ::-webkit-scrollbar-track { background-color: transparent; }
      ::-webkit-scrollbar-thumb { background-color: rgba(155, 155, 155, 0.5); border-radius: 10px; transition: opacity 0.3s ease; opacity: 0; }
      ::-webkit-scrollbar-thumb:hover { background-color: rgba(155, 155, 155, 0.7); }
      *:hover::-webkit-scrollbar-thumb,
      *:focus::-webkit-scrollbar-thumb,
      *:active::-webkit-scrollbar-thumb { opacity: 1; }
      * { scrollbar-width: thin; scrollbar-color: rgba(155, 155, 155, 0.5) transparent; }
    `;
    document.head.appendChild(s);
  }
  return null;
};

<RuncrateStyles />

Video generation is asynchronous. You submit a job, poll for completion, then download the MP4 result.

## Flow

```mermaid theme={"theme":"github-dark"}
graph LR
    A[Submit Job] --> B[Poll Status]
    B --> C{Completed?}
    C -->|No| B
    C -->|Yes| D[Download MP4]
```

## Endpoints

| Step     | Endpoint                   | Method |
| -------- | -------------------------- | ------ |
| Submit   | `/v1/videos`               | POST   |
| Poll     | `/v1/videos/{id}`          | GET    |
| Download | `/v1/videos/{id}/download` | GET    |

## Full Example

<CodeGroup>
  ```python Python theme={"theme":"github-dark"}
  import requests, time

  # Step 1: Submit job
  response = requests.post(
      "https://api.runcrate.ai/v1/videos",
      headers={
          "Authorization": "Bearer rc_live_YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "model": "google/veo-3.0",
          "prompt": "A cinematic sunrise over misty mountains",
          "duration": 6,
      },
  )
  job = response.json()
  print("Job ID:", job["id"])

  # Step 2: Poll for completion
  while True:
      poll = requests.get(
          f"https://api.runcrate.ai/v1/videos/{job['id']}",
          headers={"Authorization": "Bearer rc_live_YOUR_API_KEY"},
      )
      data = poll.json()
      if data["status"] == "completed":
          break
      time.sleep(5)

  # Step 3: Download the video
  video = requests.get(
      f"https://api.runcrate.ai/v1/videos/{job['id']}/download",
      headers={"Authorization": "Bearer rc_live_YOUR_API_KEY"},
  )
  with open("video.mp4", "wb") as f:
      f.write(video.content)
  ```

  ```javascript JavaScript theme={"theme":"github-dark"}
  // Step 1: Submit job
  const res = await fetch("https://api.runcrate.ai/v1/videos", {
    method: "POST",
    headers: {
      "Authorization": "Bearer rc_live_YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "google/veo-3.0",
      prompt: "A cinematic sunrise over misty mountains",
      duration: 6,
    }),
  });
  const job = await res.json();

  // Step 2: Poll for completion
  const poll = async () => {
    const r = await fetch(`https://api.runcrate.ai/v1/videos/${job.id}`, {
      headers: { "Authorization": "Bearer rc_live_YOUR_API_KEY" },
    });
    const data = await r.json();
    if (data.status === "completed") return;
    await new Promise(resolve => setTimeout(resolve, 5000));
    return poll();
  };
  await poll();

  // Step 3: Download
  const video = await fetch(`https://api.runcrate.ai/v1/videos/${job.id}/download`, {
    headers: { "Authorization": "Bearer rc_live_YOUR_API_KEY" },
  });
  ```

  ```bash curl theme={"theme":"github-dark"}
  # Step 1: Submit job
  curl https://api.runcrate.ai/v1/videos \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer rc_live_YOUR_API_KEY" \
    -d '{"model": "google/veo-3.0", "prompt": "A cinematic sunrise", "duration": 6}'

  # Step 2: Poll status
  curl https://api.runcrate.ai/v1/videos/VIDEO_ID \
    -H "Authorization: Bearer rc_live_YOUR_API_KEY"

  # Step 3: Download
  curl https://api.runcrate.ai/v1/videos/VIDEO_ID/download \
    -H "Authorization: Bearer rc_live_YOUR_API_KEY" \
    --output video.mp4
  ```
</CodeGroup>

## Parameters

| Parameter      | Type    | Description                 |
| -------------- | ------- | --------------------------- |
| `model`        | string  | Model ID (required)         |
| `prompt`       | string  | Text description (required) |
| `duration`     | integer | Video length in seconds     |
| `aspect_ratio` | string  | `16:9` or `9:16`            |

Duration options vary by model. Some models use discrete choices (e.g., 5s or 10s), others support a continuous range.

## Available Video Models

| Model             | Durations | Pricing    | Notes                      |
| ----------------- | --------- | ---------- | -------------------------- |
| **Sora 2**        | 4, 8, 12s | Per second | OpenAI's video model       |
| **Sora 2 Pro**    | 4, 8, 12s | Per second | Higher quality variant     |
| **Veo 2.0**       | 5–8s      | Per second | Google's video model       |
| **Veo 3.0**       | 4, 6, 8s  | Per second | Latest Google model        |
| **Veo 3.0 Audio** | 4, 6, 8s  | Per second | Video with generated audio |
| **Kling v3**      | 3–15s     | Per second | Continuous duration range  |
| **Seedance**      | 2–12s     | Per second | ByteDance's model          |
| **Hailuo 02**     | 6, 10s    | Per second | MiniMax's model            |

## Job Statuses

| Status       | Meaning                  |
| ------------ | ------------------------ |
| `queued`     | Job is waiting to start  |
| `processing` | Video is being generated |
| `completed`  | Ready for download       |
| `failed`     | Generation failed        |
