Error codes reference

Ikke oversatt ennå – vist på engelsk.

Every failure is a 4xx or 5xx response with an application/problem+json body as defined in RFC 9457. The code field is the contract: it never changes meaning. The detail text is written for humans and may be reworded at any time, so do not match on it.

The problem document

{
  "type": "https://langapi.xyz/docs/errors#text-too-long",
  "title": "Text too long",
  "status": 400,
  "code": "text_too_long",
  "detail": "Request contains 61204 characters; your plan allows 50000 per request.",
  "request_id": "01JAX3M1P5R7T9V1X3Z5B7D9F1",
  "max_characters": 50000,
  "characters": 61204
}

type, title, status, code, detail and request_id are always present. Some codes append further fields; treat unknown fields as optional.

Status codes at a glance

StatuscodeMeaning
400validation_errorA parameter is missing, malformed or inconsistent
400invalid_target_langtarget_lang is not a supported target
400invalid_source_langsource_lang is not a supported source
400too_many_textstext has more than 50 entries
400text_too_longThe request exceeds your plan's characters per request
400bad_requestDashboard only: an unknown checkout kind or plan was submitted
401unauthorizedMissing, malformed or unknown API key
401key_revokedThe key has been revoked
402quota_exceededIncluded volume used and the overage cap reached
402credit_exhaustedPrepaid balance too low for this request
403forbiddenDashboard only: not signed in, no team selected or insufficient role
403glossary_limit_reachedYour plan's glossary count is used up
404not_foundNo such endpoint or resource
404glossary_not_foundNo glossary with that id in your team
405method_not_allowedWrong HTTP method for this path
419csrf_invalidDashboard only: a form was submitted with a missing or stale token
429rate_limitedRequests per second exceeded
500internal_errorAn unexpected failure on our side
503engine_unavailableThe translation engine did not deliver a result
503service_unavailableA supporting service is temporarily down

Extra fields and headers by code

codeAdditional fieldsHeader
too_many_textsmax_texts
text_too_longmax_characters, characters
unauthorizedWWW-Authenticate: Bearer realm="langapi"
quota_exceededcharacter_limit, overage_cap_minor, period_end
credit_exhaustedbalance_minor, required_minor, currency
glossary_limit_reachedmax_glossaries
method_not_allowedAllow listing the accepted methods
rate_limitedlimitRetry-After in seconds
engine_unavailableRetry-After: 5
service_unavailableRetry-After: 5

Code by code

bad_request

Raised by the dashboard's checkout pages when the submitted plan or checkout kind is unknown. The API endpoints under /v1 do not produce it; a malformed API request is reported as validation_error.

credit_exhausted

Your prepaid balance does not cover the characters in this request. The document tells you the balance and what the request would have cost, both in minor currency units. Top up in the dashboard; the request itself was not charged.

csrf_invalid

Status 419. Raised by dashboard forms whose anti-forgery token is missing or stale, never by the API. Reload the page and submit again.

engine_unavailable

The engine was tried twice and did not return a usable translation. The reservation has been released. Wait for Retry-After seconds and resend with exponential backoff.

forbidden

A dashboard code: the visitor is not signed in, has no team selected, is not a member of the team, or lacks the role a page requires. API keys are never subject to role checks, so /v1 requests do not receive it.

glossary_limit_reached

The team already has as many glossaries as the plan allows. Delete one that is no longer used, or move to a plan with a higher limit.

glossary_not_found

The id is not a valid ULID, or no glossary with that id belongs to your team. Glossaries of other teams are indistinguishable from non-existent ones.

internal_error

Something failed that should not have. Retry once; if it persists, contact support and include the request_id.

invalid_source_lang

The source_lang value is not one of the 36 base codes. Note that regional variants are not valid sources.

invalid_target_lang

The target_lang value is not one of the 38 target codes. Fetch GET /v1/languages?type=target for the list.

key_revoked

The key was recognised but has been revoked. Deploy the current key; see API keys and authentication for a rotation procedure that avoids this.

method_not_allowed

The path exists, the method does not. The Allow header names the methods that do.

not_found

The path matches no endpoint. This is answered before authentication, so it does not tell you whether the key was valid.

quota_exceeded

The period's included characters are used up and the overage cap has been reached. Raise the cap in the dashboard or wait for period_end.

rate_limited

More requests in the last second than the plan allows. limit in the document and X-RateLimit-Limit in the header tell you the number. Wait for Retry-After and try again; see Request rate limits.

service_unavailable

A backing service other than the engine — for example the store behind the rate limiter and quota counters — could not be reached. Retry after a few seconds.

text_too_long

The sum of characters across all entries of text exceeds the per-request limit of your plan. Split the batch; the document reports the limit and the count you sent.

too_many_texts

More than 50 entries in text. Send several requests.

unauthorized

No key, a key that does not match the la_live_/la_test_ pattern, or a key that is not in our records. Check the header format first.

validation_error

The catch-all for parameter problems: an empty string in text, an unknown formality value, more/less on a target without formality support, context longer than 2,000 characters, a glossary without source_lang or with a mismatching pair, a malformed JSON body. The detail names the field.

What to retry

OutcomeCodes
Retry with backoffrate_limited, engine_unavailable, service_unavailable, internal_error
Do not retry unchangedAll other 4xx — the same request will fail the same way

A request that fails is never charged: 429 and 503 are rejected before or after the reservation, and in the latter case the reservation is rolled back.

A minimal retry wrapper

const RETRY = new Set(['rate_limited', 'engine_unavailable', 'service_unavailable', 'internal_error']);

async function callTranslate(payload, key, maxAttempts = 5) {
  for (let n = 0; n < maxAttempts; n++) {
    const res = await fetch('https://api.langapi.xyz/v1/translate', {
      method: 'POST',
      headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    if (res.ok) return res.json();

    const problem = await res.json();
    if (!RETRY.has(problem.code)) {
      throw new Error(`${problem.code} (${problem.request_id}): ${problem.detail}`);
    }
    const seconds = Number(res.headers.get('Retry-After') ?? 2 ** n);
    await new Promise((r) => setTimeout(r, seconds * 1000 + Math.random() * 250));
  }
  throw new Error('translate: retries exhausted');
}

Keep the request id

Successful and failed responses alike carry X-Request-Id, and problem documents repeat it as request_id. Log it alongside your own correlation id. It is the one piece of information that lets us locate a specific request.

Engine errors stay internal

Messages, status codes and headers from the translation engine are never passed through to you. An engine failure is logged on our side without your text and surfaces to you only as engine_unavailable.

Revidert 7. sep. 2026, 00:00