Documentation menu

Errors

Every HTTP status and error message the FluentC API returns, what causes it, and which ones are safe to retry.

View as Markdown

Error shape

Errors are JSON with a single error string, and the HTTP status tells you the class of problem.

json
{ "error": "Target language 'es' is not enabled for this site." }

Branch on the status code first. Match on the message only for the specific cases below; the messages are quoted exactly as the API returns them.

The one exception: a batch job that couldn't be translated is not an HTTP error. Batch results returns 200 with "status": "failed" and an error string.

Status codes

StatusMeaningRetry?
200Success. For batch results, check status.n/a
401Authentication failed.No. Fix the key.
403The key is valid but the account can't make this request.No. Fix the account.
422The request is invalid.No. Fix the request.
500Something went wrong on our side.Yes, with backoff.

401 Unauthorized

MessageCause
API key (Site UUID) is missingThe Authorization header is absent or empty.
Invalid API key: Site not found.The key is wrong, has extra characters, or has a Bearer prefix.
Invalid API key: Associated company not found.The key's account can't be resolved. Contact us.

403 Forbidden

MessageCause
Access denied: Translations are disabled for this site.Translation is switched off for the key's site.
Subscription error: ...The subscription isn't active, or has no languages. The text after the colon says which.
Usage limit error: ...A usage limit was reached. The text after the colon says which.

422 Unprocessable Entity

MessageEndpointCause
Input is missingtranslate, checklanguageinput is empty or absent.
Invalid or missing input format. Allowed formats: text, html, jsontranslateinput_format isn't one of the three.
Invalid or missing input format. Allowed formats: text, htmlchecklanguageinput_format isn't text or html.
Invalid or missing target language code.translatetarget_language isn't two or three lowercase letters.
Target language 'xx' is not enabled for this site.translateValid code, but not enabled for your key.
Invalid source language code: 'xx'.translatesource_language isn't two or three letters.
Source language 'xx' is not enabled for this site.translateValid code, but not enabled for your key.
Invalid or missing mode. Allowed modes: batch, real-timetranslatemode is absent or unknown.
Realtime translation is not supported for this agent.translatereal-time on a Batch plan key.
Agent translation is not supported for this site.translateThe key isn't set up for the translation API.
Invalid JSON formattranslateinput_format is json but input isn't valid JSON.
job_id (hash_key) is missingresultsThe body has no job_id.

500 Internal Server Error

json
{ "error": "An unexpected error occurred during authentication." }

Retry with exponential backoff. If it keeps happening, contact us with the time of the request and the job_id if there was one.

Retrying

  • Do retry 500 responses and network timeouts. Wait 1 second, then 2, 4, 8, up to a limit you choose, and add a little random jitter.
  • Back off if you hit a plan limit. Rate limits depend on your plan; the Batch plan allows 20 calls per hour. Treat 429 the same way as 500.
  • Don't retry 401, 403 or 422 unchanged. They will fail the same way.
  • Batch requests are safe to resubmit. The job_id is deterministic for the same input and target language.
js
async function translateWithRetry(body, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch("https://api.fluentc.ai/ai_agent/translate", {
      method: "POST",
      headers: {
        Authorization: process.env.FLUENTC_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });
    if (res.ok) return res.json();

    const retryable = res.status === 429 || res.status >= 500;
    if (!retryable || i === attempts - 1) {
      const { error } = await res.json().catch(() => ({}));
      throw new Error(`${res.status}: ${error ?? res.statusText}`);
    }
    const delay = 1000 * 2 ** i + Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, delay));
  }
}

Something unclear, or missing? Tell us.