Welcome to the xMode API
Generate AI images and (soon) videos from a single REST endpoint.
Introduction
xMode is a REST API for AI image and video generation. You integrate it into your product, your end-users trigger generations, and you pay one consolidated bill in xTokens.
Every request is tagged with the email of YOUR end-user — the real person inside your product who triggered the generation. This is required, not optional: it gives you the ability to monitor, list, and remove a specific user's content, and it gives us a clear chain of responsibility if anything is misused.
- Async by default — pick polling OR webhookPOST /v1/generations returns `202` with `{ requestId, pollUrl, status: "queued" }` immediately. Get the result either by polling `GET /v1/generations/:requestId` (recommended every 5 s) or by passing `webhookUrl` and receiving a signed POST when the generation completes.
- Survives restarts and traffic spikesYour request is durably queued before we reply. Server restarts, network blips, and bursts above the upstream rate limit do not lose work — we retry transparently and the result is waiting when the worker picks it up.
- You are accountable for your end-usersYou hold one API key. Every request carries `endUserEmail`. You are responsible for what those users generate — keep an eye on activity and act on abuse, or your account may be suspended.
- 24-hour storage by defaultEvery generated image is stored on our CDN for 24 hours, no extra cost. After that the URL stops working. Need longer? See the Storage plan section below.
- No vendor lock-in on outputImage URLs are signed but otherwise standard HTTPS. Save them or proxy them however you want.
Machine-readable spec. If you use Postman, Insomnia, n8n, ChatGPT custom GPT actions, or any tool that imports OpenAPI — point it at `https://api.xmode.ai/openapi.json`. The spec is regenerated from our Zod schemas automatically.
Authentication
Every request must include an API key in the `Authorization` header. Keys look like `xm_live_…` and are issued in your dashboard.
- 1Sign in to your dashboardOpen the dashboard and log in with your account email.
- 2Create an API keyGo to **Settings → API Keys → Create new**. Give it a memorable name (e.g. "production-server"). Copy the key once — we never show it again.
- 3Send it as a Bearer tokenAdd the header `Authorization: Bearer xm_live_<your-key>` to every request.
Example request (async — returns 202 + requestId)
# 1. Submit — returns immediately with a requestId
curl 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":"hello world"}'
# → 202 Accepted
# {
# "requestId": "req_3xN7kQ1aJpL9wDvE",
# "status": "queued",
# "pollUrl": "https://api.xmode.ai/v1/generations/req_3xN7kQ1aJpL9wDvE",
# ...
# }
# 2. Poll until status="succeeded" (typically 10–60 s)
curl https://api.xmode.ai/v1/generations/req_3xN7kQ1aJpL9wDvE \
-H "Authorization: Bearer xm_live_<your-key>"Security tips
- Treat keys like passwords. Keep them on your server. Never embed them in client code, mobile apps, or browser bundles.
- Rotate keys regularly. Compromised keys can be revoked from the dashboard.
- One key per environment is best practice — separate production from staging from CI.
Async lifecycle
Every generation moves through a small state machine. The same shape is returned by GET /v1/generations/:requestId and inside a webhook delivery — only the `status` field changes.
queuedWe accepted the request, debited xTokens, and pushed it to the worker queue. The worker has not started yet.processingA worker has picked up the request and is calling the model. Typical duration: 10–60 seconds.succeededGeneration finished. The response now includes `images[]` with signed URLs (valid 23 hours) and `cost.xTokens`.failedGeneration failed terminally. The response includes `error.code` and `error.message`. xTokens are refunded automatically.expiredMore than 23 hours have passed since success — the signed URLs are no longer fetchable. The metadata record is kept for 90 days for your audit trail.
Poll once every 5 seconds. Most generations finish within 10–60 seconds. Stop polling once `status` is one of `succeeded`, `failed`, or `expired`.
Webhook delivery (optional)
Pass `webhookUrl` in the create request and we will POST the final record to it once the generation reaches a terminal status. The body is identical to what GET /v1/generations/:requestId would return at that moment. Each delivery is HMAC-signed so you can verify it came from us — and replay-protected via a timestamp.
Headers we send
X-XMode-Signaturev1=<hex>Hex-encoded HMAC-SHA256 of `"<timestamp>.<rawBody>"` using your account webhook secret. Use a timing-safe equality check.
X-XMode-Timestamp<unixSeconds>Unix seconds when we built the payload. Reject deliveries older than 5 minutes — that is the replay window.
X-XMode-Request-Id<requestId>Mirror of the requestId in the body. Use it for your own dedup key — we may redeliver on retry.
We retry on network errors and 5xx responses with exponential backoff (up to 5 attempts via our durable queue). 4xx responses are treated as terminal — fix the endpoint and we will stop trying. We never follow redirects (3xx is treated as terminal too).
Your `webhookUrl` MUST be public HTTPS on port 443. We resolve the hostname before connecting and refuse private/loopback/link-local IPs to prevent SSRF — internal hostnames will fail with a terminal `delivery_failed`.
Verify in Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyXModeSignature(req, secret) {
const ts = req.headers['x-xmode-timestamp'];
const sig = req.headers['x-xmode-signature']; // "v1=<hex>"
if (!ts || !sig?.startsWith('v1=')) return false;
// Replay protection — reject anything older than 5 minutes.
const ageSec = Math.floor(Date.now() / 1000) - Number(ts);
if (Number.isNaN(ageSec) || ageSec < 0 || ageSec > 5 * 60) return false;
const expected = createHmac('sha256', secret)
.update(`${ts}.${req.rawBody}`)
.digest('hex');
const received = sig.slice('v1='.length);
if (expected.length !== received.length) return false;
return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(received, 'hex'));
}Storage & expiry
Every successful generation is uploaded to our CDN and you receive a signed URL in the response. Images are kept for 24 hours by default. After that the URL returns 404 and the bytes are deleted.
If you only need an image short-term (preview, single-use generation), the free 24-hour window is enough. If you ship persistent UX (a user gallery, a brand asset library, etc.) you should either save the bytes yourself the moment you receive them, or wait for the Storage plan.
Acceptable use & account responsibility
xMode runs strict content and compliance policies. As the API-key holder you are accountable for everything generated under your account — including by the end-users you onboard. Read this section before going live.
- You attribute every requestEvery call to the generation API requires `endUserEmail`. This is the real, stable identifier of the person inside your product who triggered the generation. Do not pass a fake address, a shared placeholder, or a different end-user's email — these are policy violations.
- You monitor your end-usersYou are expected to look at usage per end-user (using the listing endpoints under that email) and to act when an end-user produces disallowed content or attempts abuse. We block obvious policy violations on our side, but the first line of defence is you.
- You take action on abuseIf an end-user violates the rules — disallowed content, prompt-injection of safety controls, attempts to extract personal data of others, mass-generation for resale, etc. — remove that end-user's access in your product and call `DELETE /v1/end-users/{email}` to wipe their generations. If you do nothing, the responsibility shifts to you.
- Inaction can suspend your accountRepeated policy violations under the same `endUserEmail` that the owner does not address can lead to throttling, suspension, or termination of your API account. We will reach out before suspending where possible, but the policy is enforced — not best-effort.
- No bypass mechanismsDo not attempt to circumvent content filters, lie about request origin, or call the upstream provider directly with our keys. These actions immediately suspend the account.
These rules exist so legitimate builders can ship fast without inheriting the abuse caused by other tenants. The xMode team is small; we cannot review every prompt — we rely on you to police your own corner of the product.
Ready to generate?
The active image model is xSD 4.5. See its full reference, parameters and examples.
Continue to xSD 4.5