POST /detect
Detect the language of one text or a batch of texts without translating.
POST /detect
Detect the language of text without translating it. Send one string as text, or up to 100 strings as texts. Requires authentication.
Detection runs on a local n-gram model, so it is fast and deterministic. It does not consume the monthly character quota, but it is rate-limited per operator token.
Request
POST /api/v1/detect
Authorization: Bearer opt_your-token
Content-Type: application/json
{
"text": "Bonjour tout le monde, comment allez-vous?",
"workspace": "my-workspace",
"project_slug": "marketing"
}Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
text | string | One of text/texts | Text to detect. Max 5,000 characters. |
texts | string[] | One of text/texts | Batch of texts. 1–100 items, each non-empty and max 5,000 characters. |
workspace | string | No | Workspace slug or id. Required when the token can access multiple workspaces. |
project_slug | string | No | Project slug to attribute the detection to. |
project_id | string | No | Deprecated: use project_slug. |
Pass either text or texts, not both. Any workspace member can detect; unlike translation, the owner or admin role is not required.
Response (200) — single text
{
"language": "fr",
"languageName": "French",
"confidence": 0.569,
"reliable": true,
"supported": true,
"supportedCode": "fr",
"candidates": [
{ "language": "fr", "confidence": 0.569 },
{ "language": "hu", "confidence": 0.028 },
{ "language": "en", "confidence": 0.011 }
],
"inputCharacters": 42,
"logId": "t8npm0CPZfZF78B-Uq3lM",
"engine": "tinyld",
"latencyMs": 2
}Response (200) — batch
Results are returned in the same order as texts.
{
"results": [
{ "language": "de", "languageName": "German", "confidence": 1, "reliable": true, "supported": true, "supportedCode": "de", "candidates": [{ "language": "de", "confidence": 1 }], "inputCharacters": 49, "logId": "l9oWWkqMkhqaJNj8r5-77" },
{ "language": "hi", "languageName": "Hindi", "confidence": 1, "reliable": true, "supported": false, "supportedCode": null, "candidates": [{ "language": "hi", "confidence": 1 }], "inputCharacters": 43, "logId": "o_dqbp14JHlqPkEhTM6zd" },
{ "language": "und", "languageName": "Undetermined", "confidence": 0, "reliable": false, "supported": false, "supportedCode": null, "candidates": [], "inputCharacters": 2, "logId": "bJ_kJzseQ_NlxwPyCdPqu" }
],
"batchId": "sr1iANYUNPkQJIQT0mKu9",
"inputCharacters": 94,
"engine": "tinyld",
"latencyMs": 1
}Response Fields
| Field | Type | Description |
|---|---|---|
language | string | ISO 639-1 code (e.g. fr, en), or und when the language cannot be determined |
languageName | string | English name of the language |
confidence | number | Engine score from 0 to 1. Relative, not a calibrated probability |
reliable | boolean | true when the text is long enough and the top language clearly wins. Treat false as a guess |
supported | boolean | Whether the language can be used as source_lang / target_lang in /translate |
supportedCode | string | null | The Translate language code to use (e.g. en → en-US, no → nb) |
candidates | array | Up to 3 { language, confidence } alternatives, best first |
inputCharacters | number | Character count of the text |
logId | string | Detection log ID for auditing |
engine | string | Detection engine (tinyld) |
latencyMs | number | Detection time in milliseconds |
batchId | string | Batch only: shared ID for every item in the request |
Short and ambiguous text
Detection needs signal. Very short strings ("ok", "Hola"), numbers, and emoji often return und or reliable: false. For short UI strings, prefer passing an explicit source_lang to /translate over trusting detection.
Example
curl -X POST https://your-domain.com/api/v1/detect \
-H "Authorization: Bearer opt_your-token" \
-H "Content-Type: application/json" \
-d '{"texts":["Bonjour le monde","Hallo Welt, wie geht es dir?"],"workspace":"my-workspace"}'const res = await fetch("https://your-domain.com/api/v1/detect", {
method: "POST",
headers: {
"Authorization": "Bearer opt_your-token",
"Content-Type": "application/json",
},
body: JSON.stringify({ text: "Bonjour tout le monde, comment allez-vous?" }),
});
const { language, reliable, supportedCode } = await res.json();
console.log(language, reliable, supportedCode); // "fr" true "fr"import requests
response = requests.post(
"https://your-domain.com/api/v1/detect",
headers={"Authorization": "Bearer opt_your-token"},
json={"text": "Bonjour tout le monde, comment allez-vous?"},
timeout=10,
)
print(response.json()["language"]) # "fr"Errors
Detection uses the same error shape and status codes as /translate. Detection-specific validation errors:
| Status | Error |
|---|---|
| 400 | text (or texts for a batch) is required and must be non-empty |
| 400 | Pass either text or texts, not both. |
| 400 | texts must be a non-empty array |
| 400 | texts must not contain more than 100 items |
| 400 | texts[N] must be a non-empty string |
| 400 | texts[N] must not exceed 5000 characters |
| 500 | Language detection failed |
See the Error Reference for authentication, scope, and rate-limit errors.