Preparing page…
▥ Seedance 2.5 is here! ›
PricingDocsUpdatesAccount
GuidesOverviewImage APIVideo API
On this pageQuickstartAuthenticationEndpointsRoute modeBillingTasks and pollingUploadsWebhooksErrors
ResourcesModel catalogPricingAPI keysWebhook endpointsOpenAPI specificationService statusProduct updates
OverviewImage APIVideo API
Documentation

MLMux API

One API key and one request format for image and video generation models. Images come back in the response; videos run as tasks that you poll or receive by webhook.

Quickstart

  1. 01

    Create an API key

    Create a key in Console → API keys. The full key is shown only once, so store it right away, for example as MLMUX_API_KEY.

  2. 02

    Send a request

    Call an image or video endpoint with a model ID and a prompt. Usage is charged to the account that owns the key.

  3. 03

    Get the result

    Image requests return URLs in the response. Video requests return a task: poll its poll_url or subscribe to a webhook.

Authentication

Send your key in the Authorization: Bearer header on every request to https://api.mlmux.com. Keys start with sk-. The API does not accept keys in other headers or in the query string.

To check that a key works, list the models it can call:

GEThttps://api.mlmux.com/v1/models
curl https://api.mlmux.com/v1/models \
  -H "Authorization: Bearer $MLMUX_API_KEY"
Response
{
  "object": "list",
  "data": [
    { "id": "nano-banana-2", "object": "model", "owned_by": "platform" },
    { "id": "model/seedance-2.5-max", "object": "model", "owned_by": "platform" }
  ]
}

Endpoints

All endpoints are under https://api.mlmux.com. Request and response bodies are JSON unless noted.

MethodPathDescription
GET/v1/modelsList the model IDs you can call.
POST/v1/images/generationsGenerate images from a prompt.
POST/v1/images/editsEdit or combine input images. Accepts JSON or multipart.
GET/v1/images/generations/{task_id}Get an async image task. Edits use /v1/images/edits/{task_id}.
POST/v1/videos/generationsCreate a video task.
GET/v1/videos/generations/{task_id}Get a video task.
GET/v1/tasks/{task_id}Get any task by ID.
POST/v1/tasks/{task_id}/cancelCancel a task that has not finished.
POST/v1/uploadsUpload a reference file and get a URL.
GET/v1/account/balanceGet your credit balance.

Route mode

Set route_mode in the request body to choose the upstream tier. A request stays in its tier and never silently moves to another one; if the tier is turned off for the model, the request fails with route_mode_disabled. When the field is omitted, MLMux uses the route modes set on the API key, then the model default, which is official-cheap.

ValueDescription
officialThe provider's official route, billed at the provider's list price.
official-cheapA lower-cost official route. Default for new requests and API keys.

Billing

Usage is charged in credits, and 1 credit equals 1 US dollar. Video models are billed per output token; image models are billed per upstream token or per image, depending on the model. See the pricing page for rates on each route.

Task responses show estimated_charge_credits when the task is created and actual_charge_credits after it succeeds, both in credits. Webhook payloads show actual_charge_nano_credits as an integer, where 1,000,000,000 nano-credits equal 1 credit.

Check your remaining balance with GET /v1/account/balance.

Tasks and polling

Video requests, and image requests sent with "async": true, return HTTP 202 with a task. Poll the task's poll_url every few seconds until its status is succeeded, failed, expired, or canceled.

StatusDescription
queuedAccepted and waiting to start.
submittedSent to the upstream provider.
runningGenerating. progress runs from 0 to 100.
succeededFinished. The response now includes the output URLs.
failedFailed. message explains why.
expiredDid not finish within the task's time limit.
canceledCanceled through the cancel endpoint.

Cancel a task

POSThttps://api.mlmux.com/v1/tasks/{task_id}/cancel

Tasks that are queued, submitted, or running can be canceled, and their held credits are released. The response is {"id": "task_…", "status": "canceled"}. Tasks in any other status return 409 task_not_cancelable.

Safe retries

Async video and image generation requests accept an Idempotency-Key header of up to 160 characters. Sending the same key with the same body again returns the original task instead of creating a new one. Sending the same key with a different body returns 409 idempotency_key_reused. Synchronous requests and image edits do not accept this header.

Uploads

To use a local file as a reference, upload it as the multipart field file. Images, videos, and audio up to 50 MB are accepted and kept for 3 days. Pass the returned url in any URL field of a generation request.

POSThttps://api.mlmux.com/v1/uploads
Request
curl https://api.mlmux.com/v1/uploads \
  -H "Authorization: Bearer $MLMUX_API_KEY" \
  -F "file=@start-frame.jpg"
Response
{
  "url": "https://.../uploads/3f8a....jpg",
  "asset_id": 1024,
  "mime_type": "image/jpeg",
  "size_bytes": 482113,
  "asset_type": "image"
}

Webhooks

Create an endpoint in Console → Webhooks and choose the events to receive. When a request or task finishes, MLMux sends a POST request with a JSON body to your URL.

EventDescription
request.succeededA request or task succeeded.
request.failedA request or task failed. data.error_code and data.error_message explain why.
webhook.testSent when you test the endpoint in Console.
Payload
{
  "event_id": "evt_5b0d...",
  "event_type": "request.succeeded",
  "created_at": "2026-10-26T08:00:00Z",
  "data": {
    "request_id": "task_task_01a9...",
    "task_id": "task_01a9...",
    "public_model_id": "model/seedance-2.5-max",
    "api_method": "videos.generations.create",
    "image_count": 0,
    "image_resolution": "",
    "video_seconds": 8,
    "video_resolution": "720p",
    "actual_charge_nano_credits": 1790000000,
    "latency_ms": 94210
  }
}

Verify signatures

Each delivery is signed with the endpoint's signing secret (whsec_…), which is shown once when you create or rotate it. The X-MLMux-Signature header holds a Unix timestamp t and a signature v1: the hex HMAC-SHA256 of the timestamp, a period, and the raw request body. Compute the same value, compare it, and reject old timestamps.

Node.js
import crypto from "node:crypto";

// header: X-MLMux-Signature: t=1767225600,v1=5f8c...
export function verifyMLMuxSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}

Return any 2xx status within 10 seconds. MLMux makes up to 6 delivery attempts over about 11 hours. Use X-MLMux-Event-ID to ignore duplicate deliveries.

Errors

Errors share one JSON shape. Branch on code rather than message. Include request_id, which is also returned in the X-Request-ID header, when you contact support.

Error response
{
  "error": {
    "message": "Invalid API key",
    "type": "invalid_request_error",
    "code": "invalid_api_key",
    "request_id": "req_9f2c..."
  }
}
HTTPCodeMeaning
400invalid_requestThe body is not valid JSON or a field has the wrong type, such as an unknown route_mode on an image generation.
400invalid_valueA value such as resolution, size, aspect_ratio, or n is not supported by the model.
400model_not_foundThe model ID does not exist or is not available.
400invalid_video_requestA video mode, reference count, ratio, resolution, or duration is invalid.
400content_policy_violationThe prompt or an input was blocked by content moderation.
401invalid_api_keyThe API key is missing, invalid, expired, or disabled.
402insufficient_creditsThe balance cannot cover the estimated charge. Add credits and try again.
402spend_limit_exceededThe request would exceed a spend limit set in Console.
402api_key_monthly_limit_exceededThe request would exceed this API key's monthly budget.
403email_verification_requiredVerify the account email address before using the API.
403model_not_allowedThis API key is restricted to other models.
403forbidden_asset_referenceAn asset:// reference does not belong to this account.
404task_not_foundThe task does not exist or belongs to another account.
409idempotency_key_reusedThe Idempotency-Key was already used with a different body.
409task_not_cancelableThe task has already finished.
429rate_limit_exceededToo many requests per minute for this key or account.
429capacity_exhaustedEvery upstream on the selected route is busy.
502model_unavailableThe selected route has no available upstream for this model.
502generation_failedThe upstream provider failed to generate an output.
503generation_unavailableThe upstream provider is temporarily unavailable.
503route_mode_disabledThe selected route mode is turned off for this model. Send another route_mode.
504generation_timeoutThe upstream provider timed out.

429 responses include a Retry-After header. Wait that many seconds before retrying, and retry 5xx errors with exponential backoff.

NextImage API