xW 2.7 S
Image-to-video generation: animate a still image from a text prompt, with optional audio input.
xW 2.7 S turns a single input image into a short video guided by a text prompt. It supports 720p/1080p output, 2–15 second durations, an optional audio track to drive motion, and a negative prompt. The endpoint is **asynchronous**: POST returns `202` with a `requestId` and `pollUrl` immediately, and the finished video is delivered via polling (`GET /v1/videos/:requestId`) or via an HMAC-signed webhook if you supply `webhookUrl`. Signed video URLs are valid for 23 hours. Every request must be tagged with `endUserEmail` so videos can be grouped and managed per end-user inside your account.
Authentication. Add Authorization: Bearer xm_live_… to every request.
Account responsibility. Every request must include the real email of YOUR end-user via endUserEmail. You are accountable for what they generate — monitor activity and act on abuse, or your account may be suspended.
Quick example
Send a generation in 5 lines. Pick your language below.
curl -X POST https://api.xmode.ai/v1/generations \
-H "Authorization: Bearer xm_live_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"endUserEmail": "alice@your-product.com",
"model": "xW2.7S",
"prompt": "A girl dancing gracefully in a flower field, camera slowly pushing in",
"image": "https://example.com/input-image.png"
}'Request parameters
The fields you can include in the request body. Anything not listed is ignored.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
endUserEmail | string (email) | yes | — | REQUIRED. Email of YOUR real end-user inside your product — the person who actually triggered this video. We use it to attribute every request and give you a chain of responsibility: you can list, audit, and delete that user's videos. Do NOT pass a fake address, a shared placeholder, or someone else's email — that's a policy violation. Example: |
model | string | yes | — | Public model alias. Required — pass the alias of the video model you want to use (e.g. xW2.7S). Example: |
prompt | string | yes | — | English text prompt describing the motion, action, and mood you want from the input image. Max ~2000 tokens. Example: |
image | string (https URL) | yes | — | Input image to animate (publicly fetchable HTTPS URL). Supported formats JPEG, PNG (no transparency), BMP, WEBP. Width and height 240–8000 px, aspect ratio between 1:8 and 8:1, max 20 MB. Example: |
negative_prompt | string | no | — | Elements to exclude from the video. Example: |
audio_url | string (https URL) | no | — | Optional audio track (HTTPS URL) to drive the video. Supported formats WAV, MP3. Duration 2–30 seconds, max 15 MB. Example: |
resolution | "720p" | "1080p" | no | "1080p" | Output video resolution. Affects price (see Pricing). Example: |
duration | integer | no | 5 | Video duration in seconds (2–15). Billed per second of output. Example: |
prompt_extend | boolean | no | true | When enabled, the system expands and optimizes your prompt before generation. Free. |
seed | integer | null | no | null (auto) | Determinism seed (0–2147483647). Pass null or omit for an auto-generated seed. Example: |
webhookUrl | string (https URL) | no | — | Optional public HTTPS URL we will POST the final record to once the video is succeeded or failed. The body is identical to what GET /v1/videos/:requestId returns. Each delivery is HMAC-signed (`X-XMode-Signature: v1=<hex>`) and timestamped (`X-XMode-Timestamp`); reject anything older than 5 minutes. Private/loopback IPs are refused (SSRF guard). Example: |
Response
On a successful generation you receive a 200 with this shape. Output URLs are signed and valid for 23 hours.
{
"requestId": "req_8sV2kQ1aJpL9wDvE",
"model": "xW2.7S",
"status": "queued",
"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",
"pollUrl": "https://api.xmode.ai/v1/videos/req_8sV2kQ1aJpL9wDvE"
}| Name | Type | Required | Default | Description |
|---|---|---|---|---|
requestId | string | yes | — | Unique id of the video request. Use it with GET /v1/videos/:requestId to poll. |
model | string | yes | — | Public alias of the model that will produce the video. |
status | "queued" | "processing" | "succeeded" | "failed" | "expired" | yes | — | Lifecycle marker. POST always returns `queued`. GET returns the current state. `expired` means the request succeeded more than 23 hours ago and signed URLs no longer work — re-run if you need the video again. |
pollUrl | string | no | — | Present on `queued` responses only. Absolute URL to GET for status. Recommended polling cadence: every 5 seconds until terminal. |
videos | array | no | — | Present only when status=`succeeded`. Each item has `id`, `expiresAt`, optional `duration`/`resolution`, and EITHER `url` (signed, valid 23 h) OR `error: { code: "storage_failed" }` if our storage layer dropped that video. After 23 h the video is no longer accessible — save a copy on your side or re-generate. |
error | object | no | — | Present only when status=`failed`. `{ code, message }`. Same code values as the top-level error format (validation_error, content_policy, provider_error, provider_timeout, internal_error). |
cost | object | no | — | Present only when status=`succeeded`. `{ xTokens: number }`. Debited at request time; refunded automatically on `failed`. |
finishedAt | string (ISO 8601) | no | — | Present on terminal statuses (`succeeded`, `failed`, `expired`). |
endUserEmail | string | yes | — | Echoed back so you can confirm the grouping. Always lowercase. |
createdAt | string (ISO 8601) | yes | — | When the request was accepted (POST time). |
Use cases
Common patterns. Copy any block, replace the API key, and you have a runnable request.
Basic image-to-video
Animate an input image from a text prompt. Defaults to 1080p and 5 seconds.
curl -X POST https://api.xmode.ai/v1/generations \
-H "Authorization: Bearer xm_live_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"endUserEmail": "alice@your-product.com",
"model": "xW2.7S",
"prompt": "A girl dancing gracefully in a flower field, camera slowly pushing in",
"image": "https://example.com/input-image.png"
}'Higher resolution + custom duration
Set `resolution` and `duration`. A 10-second 1080p product spin.
curl -X POST https://api.xmode.ai/v1/generations \
-H "Authorization: Bearer xm_live_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"endUserEmail": "alice@your-product.com",
"model": "xW2.7S",
"prompt": "A product rotating slowly with dramatic lighting",
"image": "https://example.com/product-photo.jpg",
"resolution": "1080p",
"duration": 10
}'Audio-driven + negative prompt
Pass `audio_url` to drive the motion and `negative_prompt` to exclude artefacts.
curl -X POST https://api.xmode.ai/v1/generations \
-H "Authorization: Bearer xm_live_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"endUserEmail": "alice@your-product.com",
"model": "xW2.7S",
"prompt": "A character speaking and gesturing naturally",
"image": "https://example.com/character.png",
"audio_url": "https://example.com/speech.mp3",
"negative_prompt": "blurry, distorted face, extra limbs",
"resolution": "720p",
"duration": 8,
"seed": 42
}'Skip polling — receive a webhook
Pass `webhookUrl` and we POST the final record there once the video is done. The body is the same shape as GET /v1/videos/:requestId. Verify `X-XMode-Signature: v1=<hex>` against your account webhook secret (HMAC-SHA256 of `"<timestamp>.<rawBody>"`).
curl -X POST https://api.xmode.ai/v1/generations \
-H "Authorization: Bearer xm_live_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"endUserEmail": "alice@your-product.com",
"model": "xW2.7S",
"prompt": "Cinematic slow zoom on a lighthouse at golden hour",
"image": "https://example.com/lighthouse.jpg",
"webhookUrl": "https://your-app.example.com/hooks/xmode"
}'Limits & pricing
- Resolutions: 720p / 1080p
- Duration: 2–15 seconds
- Max input size: 20 MB input image
- Max audio size: 15 MB audio
- Prompt max tokens: ~2000
- Pricing: Billed per second of output; `1080p` bills at a higher rate than `720p`. per second (Cost = duration × per-second rate, debited at request time. Failed videos are refunded automatically.)