API DOCUMENTATION

Translate API

Organization translation for plain text and HTML. Powered by Microsoft Azure AI. Send one request — large documents are chunked on the server, then joined back into a single translation.

Overview

POST /api/v1/translate translates a string from one language to another. The public homepage translator and the organization Playground both call this endpoint. With an API key, the request uses your organization model, character limits, translation tone, and per-language localization notes. Without a key, the request uses the global service settings and is not counted against a monthly quota.

  • Text and HTML. HTML tags, classes, and ids stay in place; only visible copy is translated.
  • Automatic chunking when the source is longer than 75% of the input character limit.
  • Entity protection (on by default) keeps URLs, emails, and HTML attributes out of the model.
  • Usage is recorded only for approved, active organizations.

Authentication

Send the organization API key in either header. The key is issued when an organization is registered and approved.

x-api-key: YOUR_API_KEY
Authorization: Bearer YOUR_API_KEY

The key must belong to an approved, active organization, and translation must be enabled for that organization. A missing key is treated as public access. An unknown, unapproved, or inactive key returns 403.

Translate API

Method POST
Path /api/v1/translate
Content-Type application/json
Local http://localhost:3000/api/v1/translate

GET /api/v1/translate returns a short JSON description of the endpoint. It does not translate. The model, web search, and reasoning effort are chosen in the admin console for the organization. They are not request fields.

Request body

FieldRequiredDescription
textYesSource string. Plain text or HTML, depending on contentType.
fromLanguageYesSource language code that is enabled for the service, for example en.
toLanguageYesTarget language code. Localization notes for this code are applied when set.
contentTypeNotext (default) or html. Must be in the allowed content types.
protectEntitiesNoDefault true. Send false to translate URLs, emails, and attributes as normal text.

Response

A successful call returns HTTP 200. usage and organizationare included only when the request used a valid API key.

{
  "success": true,
  "data": {
    "originalText": "Hello, world!",
    "translatedText": "¡Hola, mundo!",
    "fromLanguage": "en",
    "toLanguage": "es",
    "contentType": "text",
    "translatedAt": "2026-10-19T12:00:00.000Z",
    "protection": {
      "enabled": true,
      "protectedCount": 1,
      "restoredCount": 1,
      "savedCharacters": 12,
      "missingPlaceholders": 0
    }
  },
  "usage": { "current": 12, "limit": 10000, "remaining": 9988 },
  "organization": { "id": "org_id", "name": "Example" },
  "performance": { "charactersProcessed": 13 }
}

Languages

Send the language code, the same value the public translator uses. A code is accepted only when an administrator has enabled it. If the code is not in that list, the API returns 400 with the unsupported language name in the error. Targets ko, zh, and ja (and the English names Korean, Chinese, Japanese) receive a fluency note and a higher output-token budget.

en
English
English
es
Spanish
Español
fr
French
Français
de
German
Deutsch
it
Italian
Italiano
pt
Portuguese
Português
ru
Russian
Русский
ja
Japanese
日本語
ko
Korean
한국어
zh
Chinese (Simplified)
中文 (简体)
zh-TW
Chinese (Traditional)
中文 (繁體)
ar
Arabic
العربية
hi
Hindi
हिन्दी
bn
Bengali
বাংলা
ur
Urdu
اردو
fa
Persian
فارسی
tr
Turkish
Türkçe
pl
Polish
Polski
nl
Dutch
Nederlands
sv
Swedish
Svenska
da
Danish
Dansk
no
Norwegian
Norsk
fi
Finnish
Suomi
cs
Czech
Čeština
sk
Slovak
Slovenčina
hu
Hungarian
Magyar
ro
Romanian
Română
bg
Bulgarian
Български
hr
Croatian
Hrvatski
sr
Serbian
Српски
sl
Slovenian
Slovenščina
et
Estonian
Eesti
lv
Latvian
Latviešu
lt
Lithuanian
Lietuvių
uk
Ukrainian
Українська
he
Hebrew
עברית
th
Thai
ไทย
vi
Vietnamese
Tiếng Việt
id
Indonesian
Bahasa Indonesia
ms
Malay
Bahasa Melayu
tl
Filipino
Filipino
sw
Swahili
Kiswahili
am
Amharic
አማርኛ
yo
Yoruba
Yorùbá
zu
Zulu
isiZulu
af
Afrikaans
Afrikaans

Text and HTML

contentType: "text" returns only the translation. Custom tone replaces the default “translation only” instruction when the organization has saved one.

contentType: "html" keeps tags, attributes, classes, and ids. Only text between tags is translated. Markdown fences such as ```html are stripped from the model output. After translation, the HTML is trimmed and extra blank lines are collapsed.

{
  "text": "<h1>Pricing</h1><p>Plans start at <a href=\"/pricing\">this page</a>.</p>",
  "fromLanguage": "en",
  "toLanguage": "fr",
  "contentType": "html"
}

Chunking

You do not send chunks. The server splits a long source, translates each piece, then joins the results into one translatedText. Chunking starts when the original text length is greater than 75% of the input character limit for that request. With the fallback limit of 50,000 characters, that threshold is 37,500. Shorter texts are one model call.

Chunk size

  • Direct OpenAI models: 1,200 characters.
  • Models with a reasoning-effort control: 2,000 characters.
  • Other models, including direct Mistral: 3,000 characters.

Plain text

The source is split on sentence endings (. ! ? followed by whitespace). Sentences are packed into the current chunk until the next sentence would pass the chunk size. The chunk is then closed and a new one starts. There is no overlap between chunks. Translated chunks are trimmed and joined with a single space.

HTML

The walker reads the document tag by tag and tracks nesting depth. A chunk closes only after a closing block tag when depth returns to zero and the chunk would otherwise exceed the size. Block tags are div, section, article, main, header, footer, nav, aside, p, and h1–h6. The closing tag stays with the chunk so the fragment is complete. If that still leaves a single piece larger than the limit, the fallback splits on sentence punctuation. HTML results are joined with newlines, extra blank lines are removed, and the combined markup is cleaned before it is returned.

How batches run

  • Direct Mistral: up to 3 chunks in parallel.
  • OfoxAI, direct OpenAI, and reasoning models: one chunk at a time, so rate limits and format errors stay isolated.
  • Direct OpenAI waits 3 seconds between chunks so the token window can recover.
  • Entity placeholders are assigned on the full document before the split, so the same URL or email keeps one token in every chunk. They are restored after the pieces are joined.
  • If any chunk fails, the whole request fails with HTTP 500 and the message from that chunk. Nothing partial is returned.

Each chunk gets its own output-token budget from the model catalog, including the per-model cap (for example GLM Flash at 4,096). Asian targets use a larger token multiplier on single-shot calls. Set a timeout of at least 120 seconds when the source is near the character limit.

Entity protection

Before the model runs, non-translatable spans are replaced with tokens such as ⟦X001⟧. The model is instructed to copy those tokens exactly. After translation they are swapped back to the original values. This keeps links, class names, and contact details stable and reduces tokens.

  • Plain text: emails, URLs, phone-like numbers.
  • HTML: those spans, plus attributes such as href, src, srcset, class, id, style, action, and data-url.
  • The same original value always maps to the same placeholder, including across chunks.
  • Disable with "protectEntities": false. Values false, "false", 0, and "0" all turn it off.

data.protection reports how many spans were mapped, how many were restored, characters saved, and how many placeholders the model dropped (missingPlaceholders). A non-zero missing count means a URL or attribute could not be put back.

Tone and localization

These are organization settings, not body fields. Translation tone (Console → API Keys) is appended to every authenticated request. When it is empty, text requests use the default: provide only the translation, with no explanation.

Localization (Console → Localization) stores a note per language code. The note for toLanguage is added to the prompt for that request only. HTML requests receive both the tone and the localization note inside the HTML rules.

Limits and errors

Input and output character limits, enabled languages, allowed content types, and the monthly request cap come from the organization when a key is present, otherwise from the global translation settings. A monthly cap applies only to authenticated calls.

StatusWhen
400Missing text, fromLanguage, or toLanguage; text over the input limit; language or content type not enabled; output over the output limit.
403Unknown, unapproved, or inactive API key.
429Monthly request limit reached. Body includes currentUsage and limit.
500A chunk failed, or the model returned an empty translation.
503Translation is disabled for the organization, or the model call failed on a single-shot request.

Code examples

Replace YOUR_API_KEY and the host. The same JSON body works in every language. Node sample below sends HTML and uses the Bearer header; the others send text with x-api-key.

curl -X POST "http://localhost:3000/api/v1/translate" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "text": "Hello, world! Visit https://example.com",
    "fromLanguage": "en",
    "toLanguage": "es",
    "contentType": "text",
    "protectEntities": true
  }'

Organization console

  • Dashboard — workspace status after login at /dashboard.
  • Playground — run a live translation with the organization key.
  • API Keys — copy or regenerate the key, read a short request sample, and save translation tone (up to 50,000 characters).
  • Localization — instructions stored per language code and applied when that code is toLanguage.
  • Usage — cached input/output characters, request counts, and cost from the organization per-million rates. Refresh is limited to once every 10 minutes.
  • Payments — API credit balance. Buy Credit records a pending purchase when you continue to checkout. An administrator adds or subtracts balance; the balance can be negative.
  • Settings — organization profile fields the account is allowed to edit.

Administrators set the model (including OfoxAI models such as GPT-6 Luna), character limits, web search, reasoning effort, and credit balance. Those controls are not part of the public translate body.

Synth Detector

POST /api/synth_v1/analyze screens plain text or HTML for AI-like writing patterns. It does not use the translation API key. The body is { "content": "...", "sanitize_ai_marks": false }. Content is limited to 5,000 characters. The result is stylometric screening, not proof of authorship. The same screen is available at /synthdetector.

curl -X POST "http://localhost:3000/api/synth_v1/analyze" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Paste the passage to screen." }'