# Video Generation

The video generation endpoints support async creation via `POST /v1/videos` and status polling via `GET /v1/videos/{id}`. Mock the full async polling lifecycle with deterministic responses.

## Endpoints

Method | Path | Format
--- | --- | ---
POST | /v1/videos | JSON (create video job)
GET | /v1/videos/{id} | JSON (poll status)

## Async Polling Pattern

Video generation is asynchronous. The `POST` endpoint returns a job ID, and the `GET` endpoint returns the current status. aimock simulates this by returning `"processing"` on the first poll and `"completed"` with the video URL on subsequent polls.

## Unit Test: Create and Poll

Using the programmatic API with vitest, register a fixture and test the full async flow.

video-polling.test.ts ts

    import { LLMock } from "@copilotkit/aimock";
    import { describe, it, expect, beforeAll, afterAll } from "vitest";

    let mock: LLMock;

    beforeAll(async () => {
      mock = new LLMock();
      await mock.start();
    });

    afterAll(async () => {
      await mock.stop();
    });

    it("creates a video job and polls for completion", async () => {
      mock.onVideo("a cat playing piano", {
        video: { url: "https://example.com/cat-piano.mp4", duration: 10 },
      });

      // Step 1: Create the video job
      const createRes = await fetch(`${mock.url}/v1/videos`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model: "sora",
          prompt: "a cat playing piano",
          duration: 10,
        }),
      });

      const createBody = await createRes.json();
      expect(createBody.id).toBeDefined();
      expect(createBody.status).toBe("processing");

      // Step 2: Poll for completion
      const pollRes = await fetch(`${mock.url}/v1/videos/${createBody.id}`);
      const pollBody = await pollRes.json();

      expect(pollBody.status).toBe("completed");
      expect(pollBody.video.url).toBe("https://example.com/cat-piano.mp4");
      expect(pollBody.video.duration).toBe(10);
    });

## JSON Fixture

fixtures/video.json json

    {
      "fixtures": [
        {
          "match": { "userMessage": "cat playing piano" },
          "response": {
            "video": {
              "url": "https://example.com/cat-piano.mp4",
              "duration": 10
            }
          }
        }
      ]
    }

## Response Format

### Create (POST /v1/videos)

- `id` — unique job identifier
- `status` — `"processing"` initially
- `created` — Unix timestamp

### Poll (GET /v1/videos/{id})

- `id` — the job identifier
- `status` — `"processing"` or `"completed"`
- `video.url` — URL of the generated video (when completed)
- `video.duration` — video duration in seconds

Video fixtures use `match.userMessage` which maps to the `prompt` field in the creation request. The async polling pattern is handled automatically by aimock.

## Record & Replay

When no fixture matches an incoming request, aimock can proxy it to the real API and record the response as a fixture for future replays. Enable recording with the `--record` flag or via `RecordConfig` in the programmatic API. Completed videos are recorded with their final URL; in-progress responses are also saved so that the async polling lifecycle can be simulated on replay without hitting the real API.

CLI sh

    npx -p @copilotkit/aimock llmock --record --provider-openai https://api.openai.com