MXO Translation API v1
Translate plain text, HTML and Markdown. Every completed translation is charged to your organization's balance. Failed translations are never charged.
Authentication
Create a key in the dashboard under API keys and send it with every request. Keep keys on your server.
Authorization: Bearer mxo_…
Models and prices
| Model | Best for | USD per million characters |
|---|---|---|
t3-flash | Fastest | $10 |
t3 | Lowest price, good quality | $4 |
t3-pro | Best quality | $100 |
Only translatable characters count: HTML tags, Markdown syntax, link targets and placeholders such as {name} are free. Each request is billed at least 20 characters. The Free plan can use t3 into zh, hi, es, ar, en, bn, pt, ur, ru and ja.
POST /v1/translate
curl https://api.mxo.ai/v1/translate \
-H "Authorization: Bearer $MXO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1234-fi" \
-d '{"text": "Save your work before clicking <b>Restart</b>.", "to": "fi", "model": "t3"}'
| Field | Type | Notes |
|---|---|---|
text | string | Required. Plain text, HTML or Markdown; the layout is kept exactly. |
to | string | Required. ISO code: fi, de, pt-br, zh-tw. Names such as “Finnish” are not accepted. |
from | string | Source ISO code. Detected when omitted. |
model | string | t3 (default), t3-flash or t3-pro. Flash and Pro need a paid plan. |
tone | 1–10 | 1 = casual, 5 = neutral (default), 7 = formal, 10 = legal. |
context | string | Up to 300 characters of facts that clarify meaning, e.g. “The person is Liisa, a woman.” Not translated. |
glossary | object | Fixed term translations, e.g. {"dashboard": "kojelauta"}. |
content_type | string | plain, html, markdown, or ui/legal for single short strings. Detected when omitted. |
Response:
{
"id": "5b1e…",
"text": "Tallenna työsi ennen kuin napsautat <b>Käynnistä uudelleen</b>.",
"model": "t3", "from": null, "to": "fi", "content_type": "html",
"characters": 37, "billable_characters": 37, "charged_usd": 0.000148,
"warnings": [],
"balance": { "plan": "free", "available_usd": 0.099852, "advance_usd": 0, … }
}
Idempotency: send an Idempotency-Key header to retry safely. A repeated key returns the first result for 24 hours and is never charged twice.
POST /v1/quote
Same body as /v1/translate. Returns the billable characters and price without translating or charging.
GET /v1/balance · GET /v1/usage
Your current balance, and this month's usage by model.
POST /v1/documents
Translate a PDF, Word (.docx), Markdown, text or HTML file (up to 20 MB). PDFs keep their original page layout, images and links. The job runs in the background; you are charged once, when the translated file is ready.
curl https://account.mxo.ai/v1/documents \
-H "Authorization: Bearer $MXO_KEY" \
-F file=@guide.pdf -F to=fi -F model=t3
# → 202 {"id": "…", "status": "queued", …}
curl https://account.mxo.ai/v1/documents/ID -H "Authorization: Bearer $MXO_KEY"
curl -o guide.fi.pdf https://account.mxo.ai/v1/documents/ID/download -H "Authorization: Bearer $MXO_KEY"
Status goes queued → extracting → translating → completed (or failed, never charged). Optional fields: from, tone, context, glossary (JSON).
Websites
GET/POST /v1/websites, GET/PATCH/DELETE /v1/websites/{id}. Fields: name, mode (proxy or self_hosted), origin, proxy_host, source_locale, target_locales (in rollout order), model, rollout (all or gradual: 3 new languages every week). Pages are translated automatically when they are first seen or change, and served under /{language}/….
Data retention: ZDR or cached
Every /v1/translate request and document upload can set "retention": "zdr" or "cache". Without it, the organization default applies (Settings → Data retention; ZDR unless changed).
- zdr (Zero Data Retention): the text and result exist only while the request runs. Nothing is written to the translation cache, and an
Idempotency-Keyretry of a completed request returns409 result_not_retainedinstead of the result (it is never charged twice). Translated documents can be downloaded once, then they are deleted (or after 1 hour). - cache: validated results are kept in the translation cache for 360 days and reused for identical requests (
"cached": truein the response). Cache hits are billed like translations. Idempotent retries return the stored result for 24 hours; documents stay downloadable for 7 days.
Website translation always uses cached state, because published pages, links and sitemaps must be stored.
Balance rules
- Your plan adds a balance every month. Unused monthly balance expires at the next renewal; purchased credit does not.
- The price is held when a request starts and charged when the translation completes. Failed translations release the hold.
- Free stops when the balance is used up. Paid plans keep working up to an advance limit; the advance is repaid from next month's balance.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request, unknown_model, no_translatable_text | Fix the request. |
| 401 | unauthorized | Missing or revoked API key. |
| 402 | insufficient_balance, advance_limit | Not enough balance. The error includes price_usd and balance. |
| 403 | model_not_in_plan, language_not_in_plan, account_blocked | Your plan doesn't allow this request. |
| 409 / 422 | request_in_progress, idempotency_key_reused | Idempotency-Key conflicts. |
| 413 | text_too_large | Split the text into smaller requests. |
| 429 | rate_limited | Slow down and retry. |
| 502 | translation_failed | The translation failed quality checks. You were not charged; retry. |
{ "error": { "code": "insufficient_balance", "message": "Not enough balance for this translation.", "price_usd": 0.12, "balance": { … } } }