Get a video
Read one video request by id — the counterpart to `GET /v1/generations/{requestId}` for `POST /v1/videos`. Same record shape, same status machine, `videos[]` instead of `images[]`.
GET /v1/videos/{requestId}
Current state of one video request.
The response is a `VideoRecord`, discriminated on `status` exactly like the image record:
- `queued` — the base record plus `pollUrl`. `processing` — the base record only. - `succeeded` — adds `videos[]`, `cost` and `finishedAt`. Each item carries `id`, `expiresAt`, its `duration` and `resolution`, plus EITHER `url` or `error: { code: "storage_failed" }`. - `failed` — adds `error: { code, message }` and `finishedAt`. xTokens are refunded automatically, applied just after the status flips. - `expired` — adds `finishedAt`. The signed URL is gone; the record is kept for 90 days.
**Video takes longer than images** — expect minutes rather than seconds. Poll every 5 seconds all the same; the loop is identical.
**Reading also reconciles.** Video runs on a provider that reports completion by callback. If that callback is delayed or never arrives, this endpoint asks the provider directly for the task's state and applies the result — so polling alone is a complete integration, with no webhook configured at all. It is rate-limited internally, so polling faster does not ask the provider more often.
Reading an image id here returns `404`, the mirror of the image endpoint's behaviour.
**Deletion is not split this way.** There is no delete under `/v1/videos`: `DELETE /v1/generations/{requestId}` removes a request by its id whatever it produced, video included, and `POST /v1/generations/bulk-delete` accepts video ids in the same batch as image ones. The rules are the ones described there — terminal states only, `409 conflict` while `queued`/`processing`, which for video is a window of minutes rather than seconds.
# Request
curl 'https://api.xmode.ai/v1/videos/req_8sV2kQ1aJpL9wDvE' \
-H "Authorization: Bearer xm_live_<your-key>"
# 200 OK — done
{
"requestId": "req_8sV2kQ1aJpL9wDvE",
"model": "xW2.7S",
"status": "succeeded",
"prompt": "A girl dancing gracefully in a flower field, camera slowly pushing in",
"endUserEmail": "alice@your-product.com",
"createdAt": "2026-06-09T19:45:15.204Z",
"finishedAt": "2026-06-09T19:48:02.551Z",
"videos": [
{
"id": "vid_4kR9wZ",
"url": "https://cdn.xmode.ai/...",
"duration": 5,
"resolution": "1080p",
"expiresAt": "2026-06-10T18:48:02.551Z"
}
]
}
# 200 OK — failed, already refunded
{
"requestId": "req_8sV2kQ1aJpL9wDvE",
"model": "xW2.7S",
"status": "failed",
"prompt": "A girl dancing gracefully in a flower field, camera slowly pushing in",
"endUserEmail": "alice@your-product.com",
"createdAt": "2026-06-09T19:45:15.204Z",
"finishedAt": "2026-06-09T19:46:10.004Z",
"error": { "code": "content_policy", "message": "Request was rejected by the content filter" }
}