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.
+ The video generation endpoints support async-style creation via
+ POST /v1/videos and status polling via GET /v1/videos/{id}, with
+ deterministic responses driven entirely by your fixture.
Endpoints
@@ -85,10 +85,15 @@Endpoints
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.
+ Real video generation is asynchronous: the POST endpoint returns a job ID,
+ and the GET endpoint returns the current status. aimock does
+ not simulate status progression on this surface — the create
+ response and every subsequent poll echo the fixture's video.status verbatim.
+ A fixture with "status": "completed" is completed immediately; a fixture with
+ "status": "processing" stays processing on every poll. If you need staged
+ progression (pending → in_progress → completed), use the
+ OpenRouter Video surface with its
+ openRouterVideo polling configuration.
Unit Test: Create and Poll
@@ -114,9 +119,13 @@Unit Test: Create and Poll
await mock.stop(); }); -it("creates a video job and polls for completion", async () => { +it("creates a video job and polls its status", async () => { mock.onVideo("a cat playing piano", { - video: { url: "https://example.com/cat-piano.mp4", duration: 10 }, + video: { + id: "video_123", + status: "completed", + url: "https://example.com/cat-piano.mp4", + }, }); // Step 1: Create the video job @@ -124,23 +133,24 @@Unit Test: Create and Poll
method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - model: "sora", + model: "sora-2", prompt: "a cat playing piano", - duration: 10, }), }); const createBody = await createRes.json(); - expect(createBody.id).toBeDefined(); - expect(createBody.status).toBe("processing"); + expect(createBody.id).toBe("video_123"); + expect(createBody.status).toBe("completed"); + expect(createBody.url).toBe("https://example.com/cat-piano.mp4"); + expect(createBody.created_at).toBeDefined(); - // Step 2: Poll for completion + // Step 2: Poll the job — the status echoes the fixture const pollRes = await fetch(`${mock.url}/v1/videos/${createBody.id}`); const pollBody = await pollRes.json(); + // The poll body is flat: { id, status, created_at, url } expect(pollBody.status).toBe("completed"); - expect(pollBody.video.url).toBe("https://example.com/cat-piano.mp4"); - expect(pollBody.video.duration).toBe(10); + expect(pollBody.url).toBe("https://example.com/cat-piano.mp4"); }); @@ -153,11 +163,12 @@JSON Fixture
{
"fixtures": [
{
- "match": { "userMessage": "cat playing piano" },
+ "match": { "userMessage": "cat playing piano", "endpoint": "video" },
"response": {
"video": {
- "url": "https://example.com/cat-piano.mp4",
- "duration": 10
+ "id": "video_123",
+ "status": "completed",
+ "url": "https://example.com/cat-piano.mp4"
}
}
}
@@ -169,27 +180,41 @@ Response Format
Create (POST /v1/videos)
- id — unique job identifier
- status — "processing" initially
- created — Unix timestamp
+ -
+
id — job identifier, taken from the fixture's video.id
+
+ -
+
status — the fixture's video.status:
+ "processing", "completed", or "failed"
+
+ created_at — Unix timestamp set when the job is created
+ -
+
url — URL of the generated video; included only when
+ status is "completed"
+
Poll (GET /v1/videos/{id})
+ The poll response is flat — there is no nested video object.
id — the job identifier
-
-
status — "processing" or
- "completed"
+ status — the fixture's video.status, echoed verbatim:
+ "processing", "completed", or "failed"
+
+ created_at — Unix timestamp from job creation
+ -
+
url — URL of the generated video; present whenever the fixture sets
+ video.url
- 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.
+ prompt field in the creation request. The fixture's
+ video.id and video.status are required — aimock echoes
+ them in the create response and on every poll, without progression.
@@ -198,9 +223,9 @@ 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.
+ Completed videos are recorded with their final URL; in-progress upstream responses are
+ saved with "status": "processing" and replay with that status verbatim,
+ without hitting the real API.