DEVELOPERS

The Mātr API

Everything Translation Studio does is one HTTP call. Send English text and a target language; get back the model's own translation, the corrected one with its scores, and the structural dimensions where the language differs most from English. Same engine, same quota, same 2,000+ languages.

API access is included in Professional. Create keys on your account page.

This page is the guide. Every operation, with its parameters, responses and error codes, is in the API reference, generated from the API's OpenAPI document.

Authentication

Every call on this page except GET /v1/languages carries a key in the Authorization header. A key is matr_live_ followed by 40 hexadecimal characters. It is shown once, when it is created, and can be revoked on its own from the account page. A key inherits the plan of the account that owns it, so it stops working if the subscription lapses or the plan no longer includes the API.

Authorization: Bearer matr_live_...

Keys can translate, read the account's email address, plan and usage, read your history, and read and change your glossary. They cannot create or revoke keys, change the plan, or export or delete the account: those need you signed in on this website. So a leaked key cannot take the account over, but until you revoke it, it can spend your quota, see the account's email address, read your translations and change your glossary.

Call the API from your own server, never from a web page, where the key would be visible to anyone who opens it.

Base URL: https://api.matrintelligence.com. Bodies are JSON in UTF-8, apart from some error answers (see Errors).

Quick start

curl:

curl https://api.matrintelligence.com/v1/translate \
  -H "Authorization: Bearer matr_live_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "The doctor told my mother to rest for two days.",
       "target_language": "sinhala"}'

Python:

import requests

r = requests.post(
    "https://api.matrintelligence.com/v1/translate",
    headers={"Authorization": "Bearer matr_live_..."},
    json={"text": "The doctor told my mother to rest for two days.",
          "target_language": "sinhala"},
    timeout=170,  # a translation can take up to 160 seconds (see Limits)
)
r.raise_for_status()
result = r.json()
print(result["corrected"])          # the corrected translation
print(result["changed"])            # True if the correction differed from the model's pick
print(result["usage"]["used"], "of", result["usage"]["limit"], "characters this period")

Node:

const r = await fetch("https://api.matrintelligence.com/v1/translate", {
  method: "POST",
  headers: {
    Authorization: "Bearer matr_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    text: "The doctor told my mother to rest for two days.",
    target_language: "sinhala",
  }),
});
if (!r.ok) {
  // Not every error is JSON (see Errors): read the code only from a JSON body.
  const json = (r.headers.get("content-type") ?? "").includes("application/json");
  const body = json ? await r.json() : {};
  throw new Error(`${r.status} ${body.error ?? r.statusText}`);
}
const { corrected, changed, divergence_top } = await r.json();

POST /v1/translate

Request fields:

FieldMeaning
textEnglish source text. Up to 5,000 characters per request on Professional; whitespace at the ends is ignored.
target_languageA language key from GET /v1/languages, such as sinhala or basque, matched without regard to case or white space at the ends.
deepOptional, default false. Scores 12 candidates instead of 8. Counts twice against the character quota.
alphaOptional, a number from 0 to 1, default 0.5. Correction strength as the weight on the model's own preference: 0.3 is the strongest correction, 0.7 the lightest. A value below 0.3 counts as 0.3, and one above 0.7 as 0.7.

Response:

{
  "baseline": "...",            // the model's first translation, before correction
  "corrected": "...",           // the translation Mātr chose
  "changed": true,              // whether it chose a different translation
  "original_rank": 3,           // its rank among the model's candidates (1 is first)
  "scores": {"model": 0.61, "umf": 0.74, "final": 0.68},
  "divergence_top": [           // where the language differs most from English
    {"dimension": "word_order", "value": 1.0},
    {"dimension": "case_marking", "value": 0.85}
  ],
  "deep": false,
  "history_id": "…",            // for GET /v1/history/{translation_id}
  "usage": {"chars_billed": 47, "used": 1290, "limit": 1000000,
            "resets_at": "2026-10-29T09:30:00.000000Z"}   // when the allowance resets
}

Characters are counted only for translations that succeed: a refused or failed call costs nothing. When the text contains terms from your glossary, the engine is asked to use their translations, up to ten terms a translation.

GET /v1/languages

Public, no key required. Returns every target language the engine serves, by English name: the key to pass as target_language, the English name, the native name, and the ISO code where the engine knows one. The native name may be empty, and the code empty or left out.

{"languages": [{"key": "basque", "name": "Basque", "native_name": "", "code": "eus"}, ...],
 "count": 2331}

History and glossary

EndpointWhat it does
GET /v1/meYour plan, its limits, and the period's usage and when it resets. It answers a key whatever the plan, so it shows why other calls are refused.
GET /v1/history?limit=20&offset=0Past translations, newest first, a page at a time: limit from 1 to 100 (20 when left out), offset from 0, and total in the answer. Professional keeps them indefinitely.
GET /v1/history/{translation_id}One translation in full: the source text, both translations and the scores. The id is translate's history_id.
GET /v1/glossaryYour required term translations, newest first.
POST /v1/glossaryAdd a term: {"source_term": "...", "target_term": "..."}, each 1 to 200 characters. Up to 200 terms.
DELETE /v1/glossary/{term_id}Remove a term, by the id the glossary lists.

Errors

A refusal from the API is JSON with a stable error code you can branch on, sometimes with details beside it, and an HTTP status that says which kind of problem it is. The codes it sends to a key:

Status and codeMeaning
401 invalid_api_key, auth_requiredA key that is unknown, revoked or malformed, or no key at all. GET /v1/me answers auth_required to both.
402 payment_failedThe subscription's last payment failed. Replace the card in the billing portal, from the account page, before the key works again.
403 api_access_requiredThe account's plan does not include the API, or it has no plan any more.
404 not_foundNo such translation in your history, no such term in your glossary, or a path the API does not have.
405 method_not_allowedThe path exists, but not with this method; the Allow header lists the methods it takes.
422 empty_text, text_too_long, invalid_languageThe request itself. text_too_long includes max_chars; invalid_language includes the allowed keys.
422 invalid_termA glossary term whose source or target is made only of spaces; field names which. A source or target with nothing in it does not match the schema: a 422 with a detail list (below).
422 glossary_fullThe glossary holds all the terms it may (max_terms): delete one first.
429 rate_limit, quota_exceededMore translate requests this minute than the plan allows, or this one would take the account past the period's characters. quota_exceeded includes used, limit and resets_at.
500 internal_errorThe API failed unexpectedly. Try again later; if it persists, tell us.
502 backend_errorThe translation failed or the engine could not be reached. Nothing was billed; retry with backoff.
503 busy, spend_capNothing was billed. busy means the engine is at capacity: retry after the Retry-After seconds (5). spend_cap means translation is paused for everyone for the rest of the UTC day, as the day's spending limit is reached; Retry-After says 3600 seconds.

Some answers carry no error:

  • 422 with a detail list: a body or parameter that does not match the schema. 400 with a detail message: a body that is not UTF-8 text.
  • HTML pages from the server in front of the API: 413 for a body over 2 MB, 502 when the API cannot be reached (while it restarts, for example), 503 for more than about ten requests a second from one address, and 504 when an answer takes more than 170 seconds.

So branch on the status first: a 502, 503 or 504 from the server in front of the API may be HTML, not JSON.

Limits

ProfessionalValue
Characters per billing period1,000,000 (deep requests count twice)
Characters per request5,000
Translate requests per minute20, per account: its keys and the website together. A request counts once it passes the input checks, even if it then fails (busy, spend_cap, quota_exceeded, backend_error).
Keys per account10
Glossary terms200, and up to ten of them used in one translation
Time to allow for a translationUp to 170 seconds: the gateway waits up to 160 seconds for the engine, then answers 502. Deep requests take longer than standard ones.

GET /v1/me shows the plan's limits, the period's usage, and when the period resets.

Need more volume, other source languages, or a deployment in your own environment? Talk to us.