API reference

One key for everything Entelecy can do

Text, vision, image, voice, video and search behind a single endpoint, in a format you already know: Chat Completions. You talk to Entelecy; Entelecy talks to the providers, holds the keys, validates the request before spending anything and bills credits on real usage.

Base URL https://api.entelecy.ai Auth Authorization: Bearer kriou_live_… Formats JSON · SSE · multipart

Overview

The Entelecy API is a gateway. It takes requests in the industry-standard shape, applies authentication, validation and metering, routes them to the right provider and returns the response essentially untouched — streaming included, chunk by chunk. In practice, if your code already talks to an LLM API, swapping the base URL and the key is usually enough.

What the gateway adds along the way:

  • A single credential. No provider key ever reaches the client — they stay on the server, and what you hold is an Entelecy kriou_live_… key.
  • Validation before spending. Image size, video duration, character ceiling and enabled model are checked at the gateway; an envelope error comes back in milliseconds, at no cost.
  • Metering at the end of the call. Real usage (tokens, seconds, characters, calls) becomes a credit debit on the wallet of the key that made the call.
  • Provider swaps without breaking the contract. The model behind each capability may change; your request shape does not change with it.

The root is public and doubles as a health probe: it answers without authentication and reports which build is live.

curl
curl https://api.entelecy.ai/ \
  -H "Accept: application/json"

# 200 OK
{
  "service": "Entelecy.Api",
  "environment": "Production",
  "timestamp": "2026-08-06T09:12:44.1180Z"
}

Authentication

Every call requires an Authorization header carrying an Entelecy key as a Bearer token. The key is created and lives in your account; the gateway validates it against Entelecy Account and keeps the result in a short cache, so that check costs almost nothing on the hot path.

http
POST /v1/chat/completions HTTP/1.1
Host: api.entelecy.ai
Authorization: Bearer kriou_live_7Qb3xk9_M2pN-VtR4sLu8Z
Content-Type: application/json

Accepted credentials:

  • kriou_live_… — production key. The normal way to integrate.
  • kriou_test_… — test key, useful for staging. Endpoints can be configured to reject it.
Heads up

A malformed, revoked or expired key returns 401 without explaining why. The key never appears in logs — not in full, not partially. If one leaks, revoke it in the account: the cached validation expires within seconds.

Conventions

Requests and responses are UTF-8 JSON, except where noted (audio and media uploads use multipart/form-data; speech synthesis returns audio bytes; transcription returns plain text). Fields the gateway doesn't know are forwarded to the provider untouched — which is what lets you use new features before they show up on this page.

Headers

Header Where Description
AuthorizationrequestBearer + Entelecy key. Required on every endpoint except the root.
Content-Typerequestapplication/json, or multipart/form-data on upload endpoints.
X-Image-ProviderrequestPicks the image provider when more than one is enabled. Optional; there is a server default.

Streaming

With "stream": true the response becomes text/event-stream: data: … lines, one per event, with no intermediate buffering. The last useful event carries the call's usage; after it comes data: [DONE].

text
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Ent"}}]}

data: {"id":"...","choices":[],"usage":{"prompt_tokens":812,"completion_tokens":214,"total_tokens":1026}}

data: [DONE]
Note

The gateway always asks the provider for the usage block, so the final usage chunk arrives whether or not you request it. If a stream ends without [DONE], treat the answer as truncated and retry — the connection was cut mid-flight.

Errors

Errors raised by the gateway always take the same shape: an error object with type, message and, where it helps, code and param. Provider errors are passed through with their original status and body.

json
{
  "error": {
    "type": "invalid_request_error",
    "message": "Campo 'model' e obrigatorio."
  }
}
Status type When it happens
400invalid_request_errorEmpty body, invalid JSON, missing required field, or an envelope rejected by one of the gateway rules.
401Missing header, malformed key, revoked key, or an environment that isn't allowed.
402insufficient_creditsBalance below the operation's minimum. The body carries the balance, the shortfall and a top-up URL.
4xx / 5xxpassed throughProvider error (rate limit, refused content, outage). Status and body arrive as they came.
503upstream_unavailableThe provider dropped before the first byte and the gateway's retries were exhausted. On streaming calls it arrives as an SSE event.

Gateway codes

These are the refusals decided before calling the provider. All return 400, cost zero credits and carry an actionable message — you can fix the request and retry without guessing.

code Description
gateway_invalid_sizesize outside the model's envelope: format, pixel step, minimum or maximum area, edge or aspect ratio.
gateway_unsupported_backgroundTransparent background requested from a model that doesn't support it, with no configured alternative.
gateway_unknown_modelModel not enabled for the endpoint. The message lists the accepted ones.
gateway_invalid_durationduration missing, not an integer, or outside the allowed range for video.
gateway_invalid_resolutionVideo resolution outside the accepted list.
gateway_invalid_inputText above the speech-synthesis character ceiling. Split it up.

402 body

json
{
  "error": {
    "type": "insufficient_credits",
    "message": "Saldo insuficiente pra chamar a API.",
    "balance": 3,
    "required": 10,
    "missing": 7,
    "plan_id": "starter",
    "renews_at": "2026-09-01T00:00:00Z",
    "upgrade_url": "https://account.entelecy.ai/plans"
  }
}

Endpoints

Twelve routes, grouped by capability. The right-hand column previews the billing unit — the detail is under Billing.

Endpoint Description Billed unit
POST /v1/chat/completionsConversation and text generation in the Chat Completions shape.tokens
POST /v1/images/generationsText-to-image generation.tokens
POST /v1/images/editsImage editing with an optional mask.tokens
POST /v1/audio/transcriptionsAudio transcription (speech → text).seconds of audio
POST /v1/audio/speechSpeech synthesis (text → speech).characters
GET /v1/audio/voicesCatalog of available voices.not billed
POST /v1/videos/generationsVideo generation (submit).generated seconds
GET /v1/videos/generations/{id}Poll a video in progress.not billed
POST /v1/videos/uploadsUpload a reference media for image-to-video.not billed
POST /v1/searchWeb search with structured results.per call
GET /Service status. Anonymous.not billed

Text — Chat Completions

A Chat Completions-compatible shape: the same body you already send to OpenAI-compatible clients works here, including tools, structured output and streaming. This is the general-purpose endpoint — chat, generation, extraction, classification, agents.

POST/v1/chat/completionssupports streaming (SSE)

Fields the gateway reads or handles. Everything else is forwarded untouched.

Field Type Description
modelrequiredstringPublic model name: loom-flash or loom-pro. A vendor id is refused with 400 — the message lists what is accepted.
effortstringHow much the model should think: none, high or max. It is a gateway parameter — translated and stripped before forwarding. Omitted, nothing is rewritten.
messagesrequiredarrayConversation turns, with role (system, user, assistant, tool) and content.
streambooleantrue turns the response into an SSE stream. Defaults to false.
max_tokensintegerCeiling on generated tokens.
temperaturenumberSampling randomness, where the model accepts it.
tools / tool_choicearray / objectTool definitions and choice policy, in the standard shape.
response_formatobjectStructured output — e.g. { "type": "json_object" }.
thinkingobjectProvider field. Same rule: only rewritten when you send effort.
reasoning_effortstringProvider field. Only touched if you send effort; otherwise it passes through.

Model and effort

Two independent axes, both in the body: model picks the tier and effort picks how much the model thinks. Deliberately separate — every combination is a config line in the gateway, not a magic number. The gateway translates both into the provider’s vocabulary and strips effort before forwarding.

model Profile When to use it
loom-flashFast and cheap, for volumeShort answers, classification, autocomplete, extraction — where latency rules.
loom-proMore capable, for hard workCode, multi-step analysis, long-form writing, agents with tools.
effort Profile When to use it
noneNo explicit reasoningFastest and cheapest. Answers directly, with no thinking step.
highReasoning onThe recommended default when the answer has to be right, not just quick.
maxReasoning at the ceilingHard problems: large refactors, long planning, correctness over cost.
Note

Without effort in the body the gateway does not touch thinking or reasoning_effort — anyone already sending those keeps working as before. And the response echoes back the same name you asked for in model (loom-flash, not the vendor id): what you send and what comes back speak the same language.

Request

curl
curl -N https://api.entelecy.ai/v1/chat/completions \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "loom-flash",
    "effort": "high",
    "stream": true,
    "messages": [
      { "role": "system", "content": "Responda em portugues do Brasil, direto ao ponto." },
      { "role": "user",   "content": "Resuma o conceito de entelequia em tres linhas." }
    ]
  }'

Response

json
{
  "id": "bf1b8201-5085-455c-9556-8ebd39a0a34e",
  "object": "chat.completion",
  "created": 1786061432,
  "model": "loom-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Entelequia e…",
        "reasoning": "(so quando o modelo pensa antes de responder)"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 812,
    "completion_tokens": 214,
    "total_tokens": 1026,
    "prompt_tokens_details": { "cached_tokens": 640 },
    "completion_tokens_details": { "reasoning_tokens": 159 }
  }
}

The response, field by field

Chat Completions format. The gateway normalizes the vendor response before returning it: model comes back with the public name you asked for, and vendor-internal fields do not pass through. Fields the vendor adds that the gateway does not yet know are forwarded — what is documented here is what is stable.

Field Type Description
idstringUnique identifier for this call. Opaque: derive nothing from its shape.
objectstringchat.completion for a full response; chat.completion.chunk for each stream event.
createdintegerCreation time, in Unix seconds (UTC).
modelstringThe public name you asked for (loom-flash). Not the vendor id.
choicesarrayList of answers. Without n, exactly one.
choices[].indexintegerPosition of this choice in the list.
choices[].message / deltaobjectThe generated message: role (assistant) and content. In a stream this field is called delta and carries the new piece, not the whole text.
….reasoningstringThe reasoning, when the model thinks before answering. It is diagnostic text, not the answer: do not render it in place of content, and do not rely on its language or format.
….reasoning_contentstringOld name for the same content, kept in parallel while clients migrate. It will go away; use reasoning.
choices[].finish_reasonstringWhy it stopped: stop (natural end), length (hit the token ceiling), tool_calls (wants to call a tool).
usageobjectUsage for the call — this is what billing reads. In a stream it arrives in the last event, with an empty choices.
usage.prompt_tokensintegerInput tokens (what you sent).
usage.completion_tokensintegerOutput tokens (what the model generated), reasoning included.
usage.total_tokensintegerThe sum. This is the number billing uses.
…prompt_tokens_details.cached_tokensintegerThe part of the input that hit the prompt cache. Repeating a large prefix is far cheaper than resending it.
…completion_tokens_details.reasoning_tokensintegerHow much of the output was reasoning. Already counted inside completion_tokens — do not add it.

The usage block is the billing basis: input, output, and the share of input that hit the prompt cache — replaying a large prefix is far cheaper than resending it cold.

Image

Image generation and editing in the standard shape, with envelope validation at the gateway. The response carries the image as base64 plus the call's token usage.

POST/v1/images/generations
Field Type Description
modelrequiredstringPublic name of the image model: loom-image. See Models.
promptrequiredstringWhat to generate. Specific prompts beat stacked adjectives.
sizestringWIDTHxHEIGHT in pixels, or auto. Validated before sending.
qualitystringQuality level the model accepts.
backgroundstringauto, opaque or transparent.
nintegerNumber of images.
output_formatstringReturned file format, where the model lets you choose.

Envelope validated at the gateway

What the model accepts is the gateway's knowledge, not your code's. Before calling the provider, the request goes through these rules:

  • Both sides must be multiples of the model's pixel step.
  • Total area must sit between the model's minimum and maximum, and the longest edge below its ceiling.
  • The aspect ratio can't exceed the model's limit.
  • A transparent background asked of a model without support is rerouted to the alternate model — and billing follows the model actually used.

Request

curl
curl https://api.entelecy.ai/v1/images/generations \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "loom-image",
    "prompt": "Fachada de uma padaria de bairro ao amanhecer, luz quente, fotografia",
    "size": "1536x1024",
    "quality": "high",
    "n": 1
  }'

Response

json
{
  "created": 1785969142,
  "data": [{ "b64_json": "iVBORw0KGgoAAAANSUhEUg…" }],
  "usage": {
    "input_tokens": 42,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens": 1568,
    "total_tokens": 1610
  }
}
POST/v1/images/edits

Editing takes JSON: the base image (one or more) and an optional mask, both base64. The gateway converts it to the multipart shape the provider expects, so you don't have to build the upload.

json
{
  "model": "loom-image",
  "prompt": "Troque o fundo por um ceu limpo no fim da tarde",
  "image": ["iVBORw0KGgo…"],
  "mask": "iVBORw0KGgo…",
  "size": "1024x1024"
}
Note

The mask marks what may change: the transparent area is the editable one. Send mask and base image at the same dimensions.

Audio

Two paths: transcribing speech into text and synthesizing text into speech. The transcription engine is selected by the model field; without it, the server default applies.

POST/v1/audio/transcriptionsmultipart/form-data
Field Type Description
filerequiredfileAudio file. Usual formats (m4a, mp3, wav, ogg, webm).
modelstringPublic name of the transcription engine: loom-audio — same name as the voice; the route says whether it is speech-to-text or text-to-speech.
languagestringISO-639 language hint (pt, en). Omitted, the language is detected.

The response is plain text (text/plain), not JSON — that's the contract Entelecy clients already consume. The audio duration measured during transcription is the billing basis.

curl
curl https://api.entelecy.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -F "[email protected]" \
  -F "model=loom-audio" \
  -F "language=pt"

# 200 OK · text/plain
Bom dia. Comecando a reuniao de quinta…
POST/v1/audio/speechreturns audio bytes
Field Type Description
inputrequiredstringText to speak. There's a per-request character ceiling; above it the gateway refuses before spending.
voicestringVoice identifier. Look it up in /v1/audio/voices.
modelstringPublic name of the voice model: loom-audio. See Models.
response_formatstringmp3 or a native format such as mp3_44100_128, opus_48000_64, pcm_24000.
voice_settingsobjectFine voice controls (stability, similarity, style), forwarded to the provider.
curl
curl https://api.entelecy.ai/v1/audio/speech \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "loom-audio",
    "input": "A entrega de quinta esta confirmada. Qualquer mudanca, aviso por aqui.",
    "response_format": "mp3_44100_128"
  }' \
  --output aviso.mp3
GET/v1/audio/voicesnot billed

Lists the voices available on the account, including the provider's premade ones. Requires authentication, is never billed, and is the correct source for the identifiers used in voice.

Video

Video generation is asynchronous: you submit the request, get an identifier and poll until the state is terminal. Image-to-video uses a reference media uploaded beforehand.

POST/v1/videos/generationsasynchronous (submit + poll)
Field Type Description
modelrequiredstringPublic name of the video model: loom-video. It covers text-to-video and image-to-video — what changes is the reference media.
promptrequiredstringThe scene, the camera movement and the pacing.
durationrequiredintegerDuration in seconds, within the allowed range. It is the billing basis, which is why automatic isn't accepted.
resolutionstringResolution within the accepted list.
curl
# 1) submit — devolve o id da predicao
curl https://api.entelecy.ai/v1/videos/generations \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "loom-video",
    "prompt": "Plano aereo de uma feira livre ao amanhecer, camera avancando devagar",
    "duration": 6,
    "resolution": "720p"
  }'

# { "data": { "id": "pred_01J8Z…", "status": "queued" } }

# 2) poll — ate status completed
curl https://api.entelecy.ai/v1/videos/generations/pred_01J8Z… \
  -H "Authorization: Bearer $ENTELECY_API_KEY"

# { "data": { "status": "completed", "outputs": [{ "url": "https://…/video.mp4" }] } }
Note

Billing is armed on submit and fired by the first poll that sees the video ready. Polling repeatedly does not double-charge; if the job fails, there is no debit.

POST/v1/videos/uploadsmultipart/form-data

Uploads the reference image for the image-to-video flow and returns the identifier that goes in the generation body. The upload is never billed.

Search

Web search with structured results — built to give an agent current context before it answers. The body is forwarded to the engine, so region, language and count parameters behave as they do upstream.

POST/v1/search
curl
curl https://api.entelecy.ai/v1/search \
  -H "Authorization: Bearer $ENTELECY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "relatorio anual industria de embalagens brasil", "gl": "br", "hl": "pt-br", "num": 10 }'

The response arrives as the engine returned it: a direct answer block where one exists, organic results, knowledge panels and so on. Billing is per successful call, regardless of how many results come back.

Models

The model field takes an Entelecy public name. It describes the capability you want; which model serves it is our call, revisited continuously. Resolution is by (name, route) — a name outside the route list is a 400 before anything is spent.

model Endpoint Description
loom-flash/v1/chat/completionsFast, cheap text for volume. Accepts effort.
loom-pro/v1/chat/completionsHigher-capability text for hard work. Accepts effort.
loom-image/v1/images/generationsImage generation. Transparent background is handled by the gateway — you do not switch names.
loom-audio/v1/audio/speechSpeech synthesis with natural Portuguese prosody.
loom-audio/v1/audio/transcriptionsAudio transcription. Same name as the voice: the route decides the direction.
loom-video/v1/videos/generationsShort video generation, from text or from a reference image.

How we choose

We are not loyal to a vendor. Every segment is a moving field — a new model each month, prices falling, capabilities shifting — and what makes sense today may not next quarter. We track the relevant families in each, measure them on our own material, and switch when it pays.

The criteria, in order:

  • Quality in Brazilian Portuguese. Measured on real customer content, not on a translated benchmark.
  • Cost per accepted result. Not price per token: the price of the answer that survived review.
  • Predictable latency. A good model that swings from 3 to 40 seconds is no good for an interactive product.
  • Contract stability. A provider that changes shapes without notice is expensive over time.

Agents

Reasoning, code and tools

Chat, text generation and extraction, reading images and documents, and the agent loop with tools. This is where the gap between models shows most — and where the effort scale pays best.

Families tracked in this segment

ClaudeGPTGeminiDeepSeekLlamaMistralQwenGrok

Image

Generation and editing

Brand assets, photographic scenes, illustration, masked editing and transparent backgrounds. We weigh prompt adherence, legible typography inside the image, and consistency across variations.

Families tracked in this segment

GPT ImageImagenFLUXMidjourneyIdeogramStable DiffusionRecraftRunway

Voice

Speech synthesis

Long narration, short interactive replies, expressive reading. The cut here is how natural it sounds in Brazilian Portuguese — most options still sound translated — plus latency and style control.

Families tracked in this segment

ElevenLabsCartesiaHumePlay.htChirpAzure NeuralOpenAI TTS

Transcription

Speech to text

Meetings, dictation, noisy field audio. Accuracy in Portuguese, per-word timing, speaker separation and cost per hour of audio all weigh in.

Families tracked in this segment

WhisperScribeDeepgram NovaAssemblyAI UniversalSpeechmaticsParakeet

Video

Text to video and image to video

Short clips for content, animating an existing image, directed camera movement. Temporal coherence, prompt adherence and cost per second drive the choice.

Families tracked in this segment

VeoSoraSeedanceKlingRunwayLuma RayHailuoWan

Search

Web with structured results

Current context so an agent can answer without hallucinating: organic results, direct answers and panels, as clean JSON. Low latency matters more than volume — an agent searches several times per task.

Families tracked in this segment

SerperExaTavilyBrave SearchPerplexity SonarSerpAPIFirecrawl
Note

This is the landscape we track per segment, not an availability catalog. What is active behind each public name is our curation and changes when something better shows up — without breaking your integration, because the name does not change with it.

Billing

Everything is billed in credits, on the wallet of the credential's owner. Each capability uses the unit that matches the real work:

Endpoint Billed unit Where the measure comes from
/v1/chat/completionstokensThe response's usage, with input, output and cache broken out.
/v1/images/*tokensThe response's usage, including generated image tokens.
/v1/audio/transcriptionsseconds of audioAudio duration measured during transcription, rounded up.
/v1/audio/speechcharactersCharacter count of the submitted text.
/v1/videos/generationsgenerated secondsDuration requested on submit, billed when the video is ready.
/v1/searchper callOne unit per successful call.

Before forwarding, the gateway checks a minimum balance for the operation — higher for image and video, which cost more. Without balance, the answer is 402 with the shortfall and a top-up link, and nothing is spent at the provider.

The debit happens after the response, on real usage, and is idempotent per call: a network retry doesn't charge twice. Calls that fail at the provider produce no debit.

Heads up

If the balance runs out between the initial check and the debit, the response has already been delivered and the debit is recorded anyway. That's the only case where a wallet can go negative — the next call comes back 402.

Implementation examples

Paste-ready code, using the same models Loom — our own product — runs in production, with the handling that usually gets skipped: insufficient balance, a chunk split mid-stream, and reading usage at the end of the call.

Streaming chat

No dependencies: fetch and TextDecoder are native on Node 18+. The parser keeps the buffer remainder because a network chunk can cut an SSE line in half.

javascript
const BASE = 'https://api.entelecy.ai';
const KEY  = process.env.ENTELECY_API_KEY;

/**
 * Chat com streaming. Devolve o texto completo e o usage do ultimo chunk.
 * O gateway sempre pede usage no fim do stream — nao e preciso configurar nada.
 */
export async function chatStream(messages, { effort = 'high', onDelta } = {}) {
  const res = await fetch(`${BASE}/v1/chat/completions`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${KEY}`,
      'Content-Type': 'application/json',
    },
    // model e effort sao eixos separados: o nome escolhe a faixa, o effort a profundidade
    body: JSON.stringify({ model: 'loom-flash', effort, stream: true, messages }),
  });

  if (!res.ok) {
    // 402 = saldo insuficiente; o corpo traz balance/required/upgrade_url
    const err = await res.json().catch(() => ({}));
    throw new Error(`${res.status} ${err?.error?.type ?? 'erro'}: ${err?.error?.message ?? ''}`);
  }

  const reader  = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '', text = '', usage = null;

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });

    // SSE: eventos separados por linha; so nos importam as linhas "data: "
    const lines = buffer.split('\n');
    buffer = lines.pop() ?? '';

    for (const line of lines) {
      if (!line.startsWith('data: ')) continue;
      const payload = line.slice(6).trim();
      if (payload === '[DONE]') continue;

      let chunk;
      try { chunk = JSON.parse(payload); } catch { continue; }   // chunk partido

      const delta = chunk.choices?.[0]?.delta?.content;
      if (delta) { text += delta; onDelta?.(delta); }
      if (chunk.usage) usage = chunk.usage;                      // ultimo chunk
    }
  }

  return { text, usage };
}

Generate an image and save it

javascript
import { writeFile } from 'node:fs/promises';

export async function gerarImagem(prompt, { size = '1024x1024' } = {}) {
  const res = await fetch(`${BASE}/v1/images/generations`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ model: 'loom-image', prompt, size, n: 1 }),
  });

  const body = await res.json();
  if (!res.ok) {
    // gateway_invalid_size chega aqui ANTES de custar credito
    throw new Error(`${body.error?.code ?? res.status}: ${body.error?.message}`);
  }

  await writeFile('saida.png', Buffer.from(body.data[0].b64_json, 'base64'));
  return body.usage;
}

Limits and good practice

  • Stream long responses. Beyond perceived speed, it avoids proxy timeouts on slow generations.
  • Retry with exponential backoff. Rate limits and provider outages are transient; gateway 4xx errors don't improve on retry.
  • Cache the stable prefix. On prompts with a repeated knowledge base, it's the easiest saving available.
  • Validate image size in your own form. The gateway refuses for free, but the round trip still costs the user time.
  • Split long text before synthesis. There is a per-request ceiling, and shorter passages sound better.
  • Keep the video identifier. Polling is the only way to retrieve the result, and it's what fires billing once it's ready.

Need a higher limit, a dedicated endpoint or a model outside this list? Talk to us at [email protected].