Sign in
ActivePOST /v1/generations

xSD 4.5

High-quality image generation with optional reference images for face/character/style consistency.

xSD 4.5 generates one or more images from a text prompt. You can pass up to 10 reference images for face anchoring, style transfer, or multi-subject composition. The endpoint is **asynchronous**: POST returns `202` with a `requestId` and `pollUrl` immediately, and the result is delivered via polling (`GET /v1/generations/:requestId`) or via an HMAC-signed webhook if you supply `webhookUrl`. Signed image URLs are valid for 23 hours. Each request must be tagged with `endUserEmail` so generations can be grouped and managed per end-user inside your account.

Authentication. Add Authorization: Bearer xm_live_… to every request.

How to get an API key

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.

Read acceptable use

Quick example

Send a generation in 5 lines. Pick your language below.

curl
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",
  "prompt": "Editorial photo of a young woman in a cobalt-blue silk gown on a rainy Tokyo street at night, neon reflections, 85mm portrait lens"
}'

Request parameters

The fields you can include in the request body. Anything not listed is ignored.

NameTypeRequiredDefaultDescription
endUserEmailstring (email)yes

REQUIRED. Email of YOUR real end-user inside your product — the person who actually triggered this generation. We use it to attribute every request and give you a chain of responsibility: you can list, audit, and delete that user's generations. Do NOT pass a fake address, a shared placeholder, or someone else's email — that's a policy violation. If an end-user generates disallowed content and you do not act, your account can be suspended (see Acceptable use).

Example: "alice@your-product.com"

promptstringyes

English text prompt describing the image. Best results follow the structure: subject + action + environment, then style + lighting + composition. For text inside the image, use double quotes (Poster with the title "Hello").

Example: "Editorial photo of a woman in a cobalt-blue silk gown on a rainy Tokyo street at night"

modelstringyes

Public model alias. Required — pass the alias of the model you want to use (e.g. xSD4.5). See the list of currently available aliases below.

Example: "xSD4.5"

referencesstring | string[]no

Reference image(s) used for face/style/character consistency. Single HTTPS URL or array of 1–10 URLs. When using multiple references, name them in the prompt (e.g. "use image_1 for the face, image_2 for the outfit") so the model knows what to copy from each.

Example: "https://example.com/face.jpg" or ["https://example.com/face.jpg", "https://example.com/outfit.jpg"]

sizestringno"2K"

Output dimensions. Either a preset (`2K`, `4K` — model picks aspect ratio when used alone) or explicit pixels (e.g. `2048x2048`, `1664x2496`, `2560x1440`). Explicit-pixel values are validated up front: total pixels must be in 3,600,000..16,777,216 and aspect ratio (W/H) in 1/16..16; out-of-bounds values are rejected with `400 validation_error` before any debit. `1K` is no longer accepted — use `2K` or larger. Combine with `aspectRatio` to pick a specific aspect under a preset. When `size` is explicit `WxH`, any `aspectRatio` is ignored (explicit `size` wins).

Example: "2048x2048"

aspectRatio"auto" | "square" | "landscape" | "portrait"no"auto"

Convenience selector for aspect ratio. Combine with a preset `size` (`2K` / `4K`) and the server resolves to explicit pixels for you (e.g. `size: "2K"` + `aspectRatio: "landscape"` → `2560x1440`). `auto` (default) lets the model pick. Silently ignored when `size` is already explicit `WxH` — explicit `size` always wins, no error is raised.

Example: "landscape"

nintegerno1

How many images to generate in this single request. 1–15. Constraint: references.length + n ≤ 15. Each image is billed.

Example: 4

seedintegernorandom (server-generated)

Determinism seed. Same seed + same prompt + same model + same other params = same output. If omitted, the server picks a random seed for you and returns it in `GET /v1/generations/:requestId` (`input.seed`), so any generation can be reproduced after the fact — even when you didn't pass one in.

Example: 42

watermarkbooleannofalse

Whether to add a small platform watermark in the corner.

guidanceScalenumberno~7.5

How strictly the model follows the prompt. Lower = more creative interpretation, higher = stricter rendering. Typical range 5–10.

Example: 7.5

responseFormat"url" | "b64_json"no"url"

How images are returned. "url" gives signed CDN URLs valid for 23 hours. "b64_json" returns base64 inline (large payloads).

sequential"auto" | "disabled"no"disabled"

Set to "auto" to generate a connected series of images where the same subject is preserved across frames (storyboards, life stages, brand-visual sets). Use together with `sequentialOptions.maxImages`. Do NOT combine with `n > 1`.

sequentialOptions.maxImagesintegerno

Number of frames in the connected series. 1–15.

Example: 4

webhookUrlstring (https URL)no

Optional public HTTPS URL we will POST the final record to once the generation is succeeded or failed. The body is identical to what GET /v1/generations/: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). See the Webhook delivery section in the Introduction for verification code.

Example: "https://your-app.example.com/hooks/xmode"

Response

On a successful generation you receive a 200 with this shape. Image URLs are signed and valid for 23 hours.

JSON
{
  "requestId": "req_3xN7kQ1aJpL9wDvE",
  "model": "xSD4.5",
  "status": "queued",
  "prompt": "Editorial photo of a cat in space, cinematic, 85mm portrait lens",
  "referencesCount": 0,
  "endUserEmail": "alice@your-product.com",
  "createdAt": "2026-05-02T19:45:15.204Z",
  "pollUrl": "https://api.xmode.ai/v1/generations/req_3xN7kQ1aJpL9wDvE"
}
NameTypeRequiredDefaultDescription
requestIdstringyes

Unique id of the generation. Use it with GET /v1/generations/:requestId to poll.

modelstringyes

Public alias of the model that will produce the images.

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 images again.

pollUrlstringno

Present on `queued` responses only. Absolute URL to GET for status. Recommended polling cadence: every 5 seconds until terminal.

imagesarrayno

Present only when status=`succeeded`. Each item has `id`, `expiresAt`, and EITHER `url` (signed, valid 23 h) OR `error: { code: "storage_failed" }` if our storage layer dropped that single image. After 23 h the image is no longer accessible — long-term storage will be available on a paid plan in the future. Save a copy on your side or re-generate.

errorobjectno

Present only when status=`failed`. `{ code, message }`. The same code values as the top-level error format (validation_error, content_policy, provider_error, provider_timeout, internal_error).

costobjectno

Present only when status=`succeeded`. `{ xTokens: number }`. Debited at request time; refunded automatically on `failed`.

finishedAtstring (ISO 8601)no

Present on terminal statuses (`succeeded`, `failed`, `expired`). When the generation reached its final state.

endUserEmailstringyes

Echoed back so you can confirm the grouping. Always lowercase.

createdAtstring (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.

Text to image

Simplest case. Just a prompt and the end-user email. Returns 1 image at default size.

curl
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",
  "prompt": "Editorial photo of a young woman in a cobalt-blue silk gown on a rainy Tokyo street at night, neon reflections, 85mm portrait lens"
}'

Single reference (face anchor)

Pass one HTTPS URL as `references`. The model preserves face/style/lighting from the reference unless overridden by the prompt.

curl
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",
  "prompt": "Make her wear a leather jacket on a snowy New York street at dusk. Cinematic still.",
  "references": "https://images.pexels.com/photos/1239291/pexels-photo-1239291.jpeg",
  "size": "1664x2496"
}'

Multiple references (face + outfit)

Pass an array and name each image in the prompt. Up to 10 references. The model needs explicit roles to know what to copy from each.

curl
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",
  "prompt": "Use image_1 for the face and image_2 for the outfit. Editorial fashion photo on a Tokyo street, 85mm lens.",
  "references": [
    "https://example.com/face.jpg",
    "https://example.com/outfit.jpg"
  ],
  "size": "1664x2496"
}'

Multiple images at once

Set `n` to generate variations in a single call. Each image is billed separately.

curl
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",
  "prompt": "Cute kitten astronaut floating in a starfield, illustration",
  "size": "2048x2048",
  "n": 4
}'

Storyboard / life stages (sequential)

Use `sequential: "auto"` with `sequentialOptions.maxImages` to get a series where the same subject is preserved across frames. Do not also pass `n`.

curl
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",
  "prompt": "Series of stylistically consistent images of the same person at four life stages: child, adolescent, adult, elderly.",
  "size": "2K",
  "sequential": "auto",
  "sequentialOptions": {
    "maxImages": 4
  }
}'

Deterministic output (with seed)

Same seed + same prompt = same image. Useful for A/B comparisons and reproducibility.

curl
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",
  "prompt": "Minimalist product photo of a black ceramic coffee mug on a white surface, soft shadow",
  "size": "2048x2048",
  "seed": 42
}'

Skip polling — receive a webhook

Pass `webhookUrl` and we POST the final record there once the generation is done. No need to poll. The body is the same shape as GET /v1/generations/:requestId. Verify `X-XMode-Signature: v1=<hex>` against your account webhook secret (HMAC-SHA256 of `"<timestamp>.<rawBody>"`).

curl
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",
  "prompt": "Polaroid-style portrait of a woman with freckles, soft daylight",
  "size": "2048x2048",
  "webhookUrl": "https://your-app.example.com/hooks/xmode"
}'

Limits & pricing

  • Max images per request: 15
  • Max reference images: 10
  • Per-image size limit: 10 MB per reference
  • Total pixels range: 3.6M – 16.7M
  • Aspect ratio range: 1/16 – 16
  • Prompt max tokens: ~2000
  • Rate limit: 500 requests / minute / API key
  • Pricing: 10 xTokens per image (Each image in `n` is billed separately. Failed generations are not charged.)
Errors follow our standard format — see all error codes →