Documentation

API reference

One OpenAI-compatible API for chat, image, and video generation across every provider. Point any OpenAI SDK at the base URL, swap the model string, and ship.

https://ottoport.ai/api/v1
Open playground
Overview

Introduction

OttoPort is a unified gateway that routes LLM, image, and video generation through a single OpenAI-compatible surface. Every request is authenticated with one key and billed against one credit balance — no per-provider accounts to juggle.

  • Chat is synchronous. Responses stream token-by-token, exactly like the OpenAI API.
  • Image & video wait on the queue. The gateway holds the request until the provider finishes and returns the result URL.
  • One catalog. Discover every model, its provider, and its price at GET /v1/models.
Get started

Quickstart

Install the OpenAI SDK, set base_url to the OttoPort gateway, and use your op- key as the API key. Your first chat request is three lines away.

pip install openai      # or: npm install openai
curl https://ottoport.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "messages": [{ "role": "user", "content": "Hello!" }]
  }'

The same client works for images and video — switch the model id and call images.generate or the videos endpoint. See the sections below.

Get started

Authentication

Every request must include an Authorization header with your secret key. Keys are prefixed with op- and are created in API Keys. Keep them server-side — never ship a key in client code.

Authorization: Bearer op-xxxxxxxxxxxxxxxxxxxxxxxx
A key is shown only once at creation. Store it in a secret manager or an environment variable such as OTTOPORT_API_KEY.
API reference

Chat completions

POST/v1/chat/completions

OpenAI-compatible chat across GPT, Claude, and Gemini. Streaming, tool use, and function calling work unchanged — OttoPort translates between the OpenAI schema and each provider.

ParameterTypeDescription
modelrequiredstringAny chat model id, e.g. claude-sonnet-5.
messagesrequiredarrayConversation as role/content objects.
streamoptionalbooleanStream tokens as server-sent events. Defaults to false.
temperatureoptionalnumberSampling temperature, 0–2.
max_tokensoptionalintegerCap on generated tokens.
top_poptionalnumberNucleus sampling cutoff.
stopoptionalstring | string[]Sequence(s) that halt generation.
curl https://ottoport.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4",
    "messages": [
      { "role": "system", "content": "You are concise." },
      { "role": "user", "content": "Explain MCP in one line." }
    ],
    "temperature": 0.7,
    "stream": false
  }'

Response

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "gpt-5.4",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 24, "completion_tokens": 18, "total_tokens": 42 }
}
API reference

Image generation

POST/v1/images/generations

Generate or edit images with GPT Image and Nano Banana models. Pass image_url to run image-to-image edits. The gateway waits for the provider and returns hosted URLs.

The same endpoint serves layer decomposition. qwen-image-layered and seedream-5.0-layers take one image_url and return one data entry per RGBA layer, bottom of the stack first, each with a layer object — its index, and on Seedream its name, z-order and bounding box. The prompt is an optional caption there, and you are billed per layer returned.

ParameterTypeDescription
modelrequiredstringImage model id, e.g. nano-banana-pro.
promptrequiredstringText description of the image. On a layer-decomposition model, an optional caption of the input that steers the split.
sizeoptionalstringe.g. 1024x1024 or 16:9.
qualityoptionalstringHow much compute the model spends, on models that list qualities — the GPT Image family and ideogram-4.5. low, medium (the default), high, plus xhigh and max on gpt-image-2.5. Priced by tier: max costs sixteen times medium.
noptionalintegerNumber of images to return.
seedoptionalintegerSeed for reproducible output.
image_urloptionalstringSource image for edits / image-to-image. Required on a layer-decomposition model.
num_layersoptionalintegerLayer models only: how many RGBA layers to split into — 2 to 10 on qwen-image-layered. seedream-5.0-layers picks its own count.
asyncoptionalbooleanAnswer with a job instead of waiting for the image. Implied by webhook_url. Poll it at GET /v1/images/generations/:id, which carries status and progress.
webhook_urloptionalstringHTTPS endpoint to notify when the job finishes, with webhook_secret. See Webhooks.
horizontal_angleoptionalnumberCamera models only (qwen-image-angles): orbit around the subject, 0–360°. With vertical_angle (-30–90°) and zoom (0–10); the prompt becomes optional.
curl https://ottoport.ai/api/v1/images/generations \
  -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "prompt": "a chrome torus on a black background, studio light",
    "size": "1024x1024",
    "n": 1
  }'

Response

{
  "created": 1736200000,
  "model": "nano-banana-pro",
  "data": [{ "url": "https://cdn.ottoport.ai/images/9f2a...png", "expires_at": "2026-01-14T00:00:00.000Z" }],
  "usage": { "cost": 0.24 }
}
API reference

Video generation

POST/v1/videos/generations

Generate video with Veo, Kling, and Seedance. Video takes minutes, so the request does not wait: it places a hold on your balance for the quoted price, queues the job and answers 202 with a job whose status is queued. Follow it by polling GET /v1/videos/generations/:id or, better, by registering a webhook. A finished job is completed with the result URLs, or failed with an error and the hold released. Files hosted by OttoPort carry expires_at; download them within three days.

The same endpoint serves depth estimation. video-depth-anything takes one video_url and nothing else — no prompt — and returns a grayscale depth video of the same length and size. It is billed per second of the source, which the gateway measures.

Every submission needs an Idempotency-Key header, a unique string of up to 255 characters such as a UUID. The key is tied to its request body, so reusing it with a different body returns 409 idempotency_key_reused.

ParameterTypeDescription
modelrequiredstringVideo model id, e.g. kling-3.0.
promptrequiredstringText description of the shot. Not taken by a depth model.
image_urloptionalstringFirst frame for image-to-video.
durationoptionalintegerClip length in seconds.
aspect_ratiooptionalstringe.g. 16:9, 9:16.
seedoptionalintegerSeed for reproducible output.
last_frame_urloptionalstringClosing frame, with image_url, on models that list first-last-frame.
reference_image_urlsoptionalstring[]Subjects the shot carries through, on models that list reference-to-video.
reference_video_urlsoptionalstring[]Reference videos — motion, a performance, a scene — on models whose capabilities list referenceMedia, within its counts and seconds. Billed per second of reference video where the upstream charges for it; measured by the gateway.
reference_audio_urlsoptionalstring[]Reference audio beside reference images or videos, on the same models. Checked, not billed.
keyframesoptionalobject[]Images pinned in time, [{ image_url, time? }] with time in seconds, on models that list keyframes-to-video. Untimed keyframes are spread evenly.
video_urloptionalstringA video to work from, on models that list video-edit or video-extend. The only field a depth model takes. An edit or a depth estimate is billed per second of this video, which the gateway measures; at most 60 seconds.
video_taskoptionalstringedit (default) restyles video_url; extend continues it for duration more seconds.
draftoptionalbooleanOn seedance-2.5: render a 480p preview instead, billed at the draft rate. Text, image and reference-image requests; leave resolution out. The job's id is its draft_id.
draft_idoptionalstringOn seedance-2.5: the id of a finished draft job of yours, to render that shot at 1080p. Send only model and this (and a webhook) — prompt, inputs, duration and ratio come from the draft, which is billed on its length. Drafts can be completed for seven days.
webhook_urloptionalstringHTTPS endpoint to notify when the job finishes. See Webhooks.
webhook_secretoptionalstringRequired with webhook_url. Your own secret; deliveries are signed with it. Never returned by the API.
curl https://ottoport.ai/api/v1/videos/generations \
  -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "model": "kling-3.0",
    "prompt": "cinematic product reveal, slow dolly, black background",
    "duration": 5,
    "aspect_ratio": "16:9",
    "webhook_url": "https://example.com/hooks/ottoport",
    "webhook_secret": "'"$OTTOPORT_WEBHOOK_SECRET"'"
  }'

# Without a webhook, poll until status is completed or failed:
curl https://ottoport.ai/api/v1/videos/generations/$JOB_ID \
  -H "Authorization: Bearer $OTTOPORT_API_KEY"

Response

// 202 Accepted
{
  "id": "7c1e9a52-...",
  "job_id": "7c1e9a52-...",
  "model": "kling-3.0",
  "status": "queued",
  "created": 1736200000,
  "updated": "2026-01-11T00:00:00.000Z"
}

// GET /v1/videos/generations/7c1e9a52-... once finished
{
  "id": "7c1e9a52-...",
  "status": "completed",
  "data": [{ "url": "https://cdn.ottoport.ai/videos/7c1e....mp4", "expires_at": "2026-01-14T00:00:00.000Z" }],
  "webhook": {
    "url": "https://example.com/hooks/ottoport",
    "deliveries": [{ "event": "video.completed", "status": "delivered", "attempts": 1, "max_attempts": 5, "response_status": 200 }]
  }
}
API reference

Webhooks

Pass webhook_url and webhook_secret when you submit a video, or an image with async, and OttoPort POSTs the finished job to that URL instead of making you poll. Webhooks are registered per job; there is nothing to set up in the dashboard.

ParameterTypeDescription
webhook_urloptionalstringAn absolute https:// URL on the default port, with no username or password in it. The host must resolve to a public address; private, loopback and link-local targets are rejected with unsafe_webhook_url.
webhook_secretoptionalstringA random string you generate and keep, e.g. openssl rand -hex 32. Use one per endpoint. OttoPort stores it only to sign deliveries.

Events

ParameterTypeDescription
video.completedoptionaleventThe job finished. data.data holds the output URLs.
video.failedoptionaleventThe job failed. data.error says why, and nothing was charged.
image.completedoptionaleventAn image job finished — the same shape, from async image generation.
image.failedoptionaleventAn image job failed; nothing was charged.
speech.completed / music.completedoptionaleventAn audio job finished, from async speech or music generation. Poll it at GET /v1/audio/speech/:id or GET /v1/audio/music/:id.
speech.failed / music.failedoptionaleventAn audio job failed; nothing was charged.

Each delivery is a JSON POST whose body is { event, data }, where data is the same job object GET /v1/videos/generations/:id returns.

POST /hooks/ottoport HTTP/1.1
content-type: application/json
user-agent: OttoPort-Webhooks/1.0
x-ottoport-event: video.completed
x-ottoport-delivery: 3f0b8d4e-...
x-ottoport-signature: t=1736200123,v1=5d2c0b...

{
  "event": "video.completed",
  "data": {
    "id": "7c1e9a52-...",
    "job_id": "7c1e9a52-...",
    "model": "kling-3.0",
    "status": "completed",
    "created": 1736200000,
    "updated": "2026-01-11T00:02:03.000Z",
    "data": [{ "url": "https://cdn.ottoport.ai/videos/7c1e....mp4", "expires_at": "2026-01-14T00:02:03.000Z" }]
  }
}

Verify the signature

x-ottoport-signature is t=<unix seconds>,v1=<hex>, where the hex is HMAC-SHA256 of `${t}.${raw body}` keyed with your webhook_secret. Compute it over the raw request body, since re-serialized JSON will not match. Compare in constant time, and reject timestamps more than five minutes old to stop replays.

# Recompute the signature by hand for a saved delivery body:
TS=1736200123
printf '%s.%s' "$TS" "$(cat body.json)" \
  | openssl dgst -sha256 -hmac "$OTTOPORT_WEBHOOK_SECRET" -hex
# Compare the digest with v1= in x-ottoport-signature.

Delivery and retries

A delivery succeeds when your endpoint answers 2xx within 10 seconds. Any other status, a timeout, a connection error or a redirect counts as a failed attempt; redirects are not followed, so point webhook_url at the final address. Failed deliveries are retried with increasing delays, 1, 5, 30 and 120 minutes, for 5 attempts over about two and a half hours. Answer quickly and do slow work in the background.

Deliveries are at least once, so the same event can arrive twice. x-ottoport-delivery stays the same across automatic retries of one delivery; key idempotency on the job id in data.id. The job's webhook field in GET /v1/videos/generations/:id shows every attempt and your endpoint's response.

Redeliver

POST/v1/videos/generations/:id/webhook

Sends a finished job's webhook again right away and resets its attempt count, so this also works after all 5 attempts have failed. Redelivery gets a new x-ottoport-delivery id. You can do the same from the Webhooks page in the dashboard, which lists every delivery by workspace.

curl -X POST https://ottoport.ai/api/v1/videos/generations/$JOB_ID/webhook \
  -H "Authorization: Bearer $OTTOPORT_API_KEY"
API reference

Collections

Generated files are temporary: their URLs stop working at expires_at, a few days after they are made. A collection keeps them for good. Collections live inside the project of the API key that creates them, so each project — and each team — has its own. Saved files stay until you delete them.

Collections unlock once the account has topped up $10 in total (refunds count against it). Before that, every collection route that would store something answers 403 collections_locked with how much is left to go; listing and deleting always work. Saved files count toward the account's storage allowance, which grows with what it has paid in: 5 GB from $10, 50 GB from $100, 200 GB from $500 and 1 TB from $2,000. Past it, saving answers 413 storage_quota_exceeded, naming the next tier. GET /v1/collections reports the tier, usage and the next tier up.

Save while you generate

Add collection to any image, video, speech or music request. Each output then carries an asset_id and an asset_url that does not expire, alongside the usual temporary url. A locked account or an unknown collection is refused before anything is generated or charged. If one file cannot be saved, the generation still succeeds and that output carries asset_error instead; save it from its url while it lasts.

ParameterTypeDescription
collectionoptionalstring | objectA collection id, or { "external_id": "…" } to address it by your own id. Add "create": true and a name to create it on first use.
curl https://ottoport.ai/api/v1/images/generations \
  -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "spring campaign hero, pastel, studio light",
    "collection": { "external_id": "campaign-spring", "name": "Spring campaign", "create": true }
  }'

# Each output carries the kept copy:
# "data": [{
#   "url": "https://cdn.ottoport.ai/images/…",          ← expires at expires_at
#   "expires_at": "2026-10-15T09:12:00.000Z",
#   "asset_id": "5b1c…",
#   "asset_url": "https://cdn.ottoport.ai/assets/…"     ← kept until deleted
# }]

Endpoints

ParameterTypeDescription
GET /v1/collectionsoptionallistThe key's project's collections, with access: whether saving is unlocked, what has been paid in, and storage used.
POST /v1/collectionsoptionalcreate{ name, description?, external_id?, metadata? }. external_id is unique within the project.
GET · PATCH · DELETE /v1/collections/:idoptionaloneRead, rename, or delete a collection together with every file in it.
GET /v1/assetsoptionallistSaved files, newest first. Filter with collection_id and kind (image, video, audio); page with limit and offset.
POST /v1/assetsoptionalsave{ url, collection, prompt?, model?, metadata? } keeps a file that was already generated or uploaded. url must be an OttoPort URL that has not expired.
GET · PATCH · DELETE /v1/assets/:idoptionalonePATCH { collection } moves it to another collection of the project; { metadata } replaces its metadata. DELETE removes the file.
POST /v1/uploadsoptionalupload{ content_type, size } returns an upload_url to PUT the file to and the url it will be read from. That URL works as any model input for a day; save it with POST /v1/assets to keep it. Uploading needs no unlock.
# 1. Ask where to put the file
curl https://ottoport.ai/api/v1/uploads -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" -d '{ "content_type": "image/png", "size": 482113 }'
# → { "upload_url": "https://…", "url": "https://cdn.ottoport.ai/uploads/….png", "headers": { "content-type": "image/png" } }

# 2. PUT the bytes there
curl -X PUT "$UPLOAD_URL" -H "content-type: image/png" --data-binary @face.png

# 3. Keep it (optional — "url" already works as a model input for a day)
curl https://ottoport.ai/api/v1/assets -H "Authorization: Bearer $OTTOPORT_API_KEY" \
  -H "Content-Type: application/json" -d '{ "url": "https://cdn.ottoport.ai/uploads/….png", "collection": "<collection id>" }'

The same collections are in the dashboard under Collections, and in the MCP server as ottoport_list_collections, ottoport_create_collection, ottoport_list_assets, ottoport_save_asset, ottoport_upload_file and ottoport_delete_asset, plus a collection argument on every generate tool.

API reference

List models

GET/v1/models

Returns the catalog in OpenAI list format, enriched with modality, provider, and pricing. Filter by modality with the modality query parameter.

ParameterTypeDescription
modalityoptionalstringFilter to chat, image, or video.
curl "https://ottoport.ai/api/v1/models?modality=video" \
  -H "Authorization: Bearer $OTTOPORT_API_KEY"

Response

{
  "object": "list",
  "data": [
    {
      "id": "kling-3.0",
      "object": "model",
      "owned_by": "kuaishou",
      "modality": "video",
      "display_name": "Kling 3.0",
      "description": "...",
      "pricing": { "perSecond": 0.084 }
    }
  ]
}
Reference

Model catalog

Every model available today, straight from the gateway registry. Chat is priced per 1M tokens (input / output); image per image; video per second.

Model IDModalityProviderPricing
gpt-6-astrachatopenai$11.08 / $55.39 per 1M
gpt-6-astra-prochatopenai$11.08 / $55.39 per 1M
gpt-6.1-solchatopenai$2.22 / $11.08 per 1M
gpt-6.1-sol-prochatopenai$2.22 / $11.08 per 1M
gpt-6-solchatopenai$2.22 / $11.08 per 1M
gpt-6-sol-prochatopenai$2.22 / $11.08 per 1M
gpt-6-lunachatopenai$0.111 / $0.554 per 1M
gpt-6-luna-prochatopenai$0.111 / $0.554 per 1M
gpt-5.6-solchatopenai$2.22 / $11.08 per 1M
gpt-5.6-terrachatopenai$2.22 / $13.29 per 1M
gpt-5.6-lunachatopenai$0.222 / $1.33 per 1M
gpt-5.5chatopenai$5.54 / $33.23 per 1M
gpt-5.2chatopenai$1.94 / $15.51 per 1M
gpt-4ochatopenai$2.77 / $11.08 per 1M
sonar-deep-researchchatperplexity$2.22 / $46.53 per 1M
gpt-5.4chatopenai$2.77 / $16.62 per 1M
gpt-5.4-minichatopenai$0.831 / $4.98 per 1M
gpt-5.4-nanochatopenai$0.222 / $1.38 per 1M
claude-fable-5.1chatanthropic$11.08 / $55.39 per 1M
claude-opus-5.5chatanthropic$4.43 / $22.15 per 1M
claude-opus-5chatanthropic$5.54 / $27.69 per 1M
claude-fable-5chatanthropic$11.08 / $55.39 per 1M
claude-opus-4.8chatanthropic$5.54 / $27.69 per 1M
claude-sonnet-5.5chatanthropic$2.22 / $11.08 per 1M
claude-sonnet-5chatanthropic$2.22 / $11.08 per 1M
claude-haiku-5.5chatanthropic$0.111 / $0.554 per 1M
claude-haiku-4.5chatanthropic$1.11 / $5.54 per 1M
gemini-3.8-flashchatgoogle$0.831 / $4.15 per 1M
gemini-3.7-flashchatgoogle$0.831 / $4.15 per 1M
gemini-3.5-flashchatgoogle$1.66 / $9.97 per 1M
gemini-3.1-pro-previewchatgoogle$2.22 / $13.29 per 1M
video-understandingchatottoport$2.22 / $13.29 per 1M
gemini-3.1-flash-litechatgoogle$0.277 / $1.66 per 1M
gemini-3.5-flash-litechatgoogle$0.332 / $2.77 per 1M
gemini-2.5-flashchatgoogle$0.332 / $2.77 per 1M
kimi-k3chatmoonshotai$3.32 / $16.62 per 1M
kimi-k2.7-codechatmoonshotai$0.756 / $3.68 per 1M
kimi-k2.6chatmoonshotai$0.693 / $3.58 per 1M
kimi-k2.5chatmoonshotai$0.394 / $2.13 per 1M
kimi-k2-thinkingchatmoonshotai$0.63 / $2.63 per 1M
kimi-k2-0905chatmoonshotai$0.63 / $2.63 per 1M
kimi-k2chatmoonshotai$0.598 / $2.42 per 1M
glm-5.3chatz-ai$1.22 / $3.82 per 1M
glm-5.3-flashchatz-ai$0.166 / $0.554 per 1M
glm-5.2chatz-ai$0.775 / $2.44 per 1M
deepseek-v4.1-flashchatdeepseek$0.155 / $0.498 per 1M
deepseek-v4-pro-0813chatdeepseek$1.25 / $3.73 per 1M
deepseek-v4-prochatdeepseek$1.06 / $2.13 per 1M
deepseek-v4-flashchatdeepseek$0.101 / $0.202 per 1M
grok-4.7chatx-ai$2.22 / $6.65 per 1M
grok-4.6chatx-ai$2.22 / $6.65 per 1M
grok-4.5chatx-ai$2.22 / $6.65 per 1M
qwen3.8-maxchatqwen$2.22 / $6.65 per 1M
qwen3.8-flashchatqwen$0.166 / $0.521 per 1M
jev-1.13decisiontypesafe$0.047 per 1M input
gpt-image-2.5imageopenai$0.026 / image
gpt-image-2.5-flareimageopenai$0.026 / image
gpt-image-2imageopenai$0.07 / image
gpt-image-1.5imageopenai$0.044 / image
gpt-image-1-miniimageopenai$0.022 / image
nano-banana-2.1imagegoogle$0.088 / image
nano-banana-2imagegoogle$0.088 / image
nano-banana-proimagegoogle$0.165 / image
nano-banana-liteimagegoogle$0.044 / image
seedream-4.7imagebytedance$0.033 / image
seedream-4.7-sequentialimagebytedance$0.033 / image
qwen-image-3.0imageqwen$0.033 / image
qwen-image-3.0-proimageqwen$0.044 / image
wan-2.7-pro-imageimagealibaba$0.083 / image
flux-2-proimageblack-forest-labs$0.033 / image
ideogram-4.5imageideogram$0.066 / image
qwen-image-anglesimageqwen$0.04 / image
qwen-image-layeredimageqwen$0.028 / layer
seedream-5.0-layersimagebytedance$0.037 / layer
midjourney-v7imagemidjourney$0.088 / image
midjourney-v8imagemidjourney$0.088 / image
midjourney-v8.1imagemidjourney$0.095 / image
midjourney-v8.2imagemidjourney$0.088 / image
seedance-2.5videobytedance$0.35 / sec
seedance-2.0videobytedance$0.227 / sec
seedance-2.0-fastvideobytedance$0.11 / sec
seedance-2.0-minivideobytedance$0.043 / sec
seedance-1.5-provideobytedance$0.063 / sec
seedance-1.5-pro-fastvideobytedance$0.05 / sec
minimax-h3videominimax$0.163 / sec
minimax-h3-maxvideominimax$0.178 / sec
flux-3videoblack-forest-labs$0.213 / sec
kling-3.0videokuaishou$0.105 / sec
kling-3.0-turbovideokuaishou$0.119 / sec
kling-3.0-provideokuaishou$0.179 / sec
kling-3.0-4kvideokuaishou$0.446 / sec
kling-o1videokuaishou$0.119 / sec
kling-o3videokuaishou$0.105 / sec
kling-o3-provideokuaishou$0.14 / sec
kling-o3-4kvideokuaishou$0.525 / sec
wan3.0-t2vvideoalibaba$0.2 / sec
wan3.0-i2vvideoalibaba$0.2 / sec
wan3.0-prime-t2vvideoalibaba$0.315 / sec
wan3.0-prime-i2vvideoalibaba$0.315 / sec
gemini-omni-1.1-flashvideogoogle$0.138 / sec
gemini-omni-flashvideogoogle$0.156 / sec
veo-3.1videogoogle$0.528 / sec
veo-3.1-fastvideogoogle$0.132 / sec
veo-3.1-litevideogoogle$0.066 / sec
hailuo-2.3videominimax$0.07 / sec
hailuo-2.3-fastvideominimax$0.048 / sec
hailuo-02videominimax$0.07 / sec
wan2.7-t2vvideoalibaba$0.125 / sec
wan2.7-i2vvideoalibaba$0.125 / sec
wan2.6-t2vvideoalibaba$0.088 / sec
wan2.6-i2vvideoalibaba$0.088 / sec
wan2.6-i2v-flashvideoalibaba$0.031 / sec
wan2.5-t2vvideoalibaba$0.063 / sec
wan2.5-i2vvideoalibaba$0.063 / sec
video-depth-anythingvideobytedance$0.063 / sec
kling-avatar-2-standardvideokuaishou$0.07 / sec
kling-avatar-2-provideokuaishou$0.144 / sec
omnihuman-1.5videobytedance$0.2 / sec
sync-lipsync-2videosync$0.063 / sec
sync-lipsync-2-provideosync$0.104 / sec
kling-lipsyncvideokuaishou$0.018 / sec
kling-2.6-motion-controlvideokuaishou$0.088 / sec
kling-2.6-pro-motion-controlvideokuaishou$0.14 / sec
kling-3.0-motion-controlvideokuaishou$0.158 / sec
kling-3.0-pro-motion-controlvideokuaishou$0.21 / sec
seedream-5.0imagebytedance$0.05 / image
seedream-5.0-liteimagebytedance$0.039 / image
gpt-4o-mini-ttsttsopenai—
eleven-v3ttselevenlabs—
eleven-turbo-2.5ttselevenlabs—
gemini-2.5-flash-ttsttsgoogle—
seed-audio-1.0ttsbytedance—
speech-2.8-turbottsminimax—
speech-2.8-hdttsminimax—
gpt-4o-mini-transcribesttopenai$0.0000607 / sec
gpt-4o-transcribesttopenai$0.000121 / sec
qwen3-asr-flashsttqwen$0.0000425 / sec
qwen3-embedding-8bembeddingqwen$0.011 per 1M input
bge-m3embeddingbaai$0.011 per 1M input
text-embedding-3-smallembeddingopenai$0.022 per 1M input
text-embedding-3-largeembeddingopenai$0.144 per 1M input
voyage-4embeddingvoyageai$0.066 per 1M input
voyage-4-liteembeddingvoyageai$0.022 per 1M input
suno-v6musicsuno—
suno-v6-minimusicsuno—
suno-v6-wildmusicsuno—
lyria-2musicgoogle—
seed-musicmusicbytedance—
Reference

Errors

Errors use standard HTTP status codes and an OpenAI-style error object with a stable code. The type mirrors code for SDK compatibility.

{
  "error": {
    "message": "`model` and `messages` are required",
    "type": "invalid_request",
    "code": "invalid_request"
  }
}
StatusCodeWhen
400invalid_requestMissing or malformed body (e.g. no model or messages).
401missing_api_keyNo Authorization: Bearer header was sent.
401invalid_api_keyKey is malformed or not recognized.
402insufficient_creditsThe account's credit balance is exhausted.
404model_not_foundThe requested model id is not in the catalog.
429rate_limitedToo many requests — back off and retry.
502upstream_errorThe upstream provider failed or timed out.
Reference

Rate limits

Limits scale with your spend tier. When you exceed them the gateway returns 429 rate_limited — back off with exponential retry and honor any Retry-After header. Need higher throughput or dedicated capacity? Talk to us.

Reference

SDKs & tools