Skip to content

Translations

Manage per-organization language config, translate questions and categories, and read translated content.

Updated 2026-05-20

Every organization has one source language (set once on creation) and zero or more target languages. Translations live alongside the source content, fetched explicitly with an Accept-Language header or appended as part of the resource itself.

Machine translation runs on demand via the AI fallback chain (OpenAI → Anthropic → Google). All translations are editable before publish — the machine pass is a starting point, not a final answer.

Language config

Read configured languages

curl https://api.thefaq.app/api/v1/acme/languages \
  -H "Authorization: Bearer $FAQAPP_API_KEY"

Response:

{
  "data": {
    "source": "en",
    "targets": ["es", "de", "fr"],
    "available": ["af", "ar", "az", "…and ~95 more"]
  }
}

Configure target languages

Target languages are configured in the dashboard at Settings → Languages. Pick from the ~95 supported BCP-47 codes; add or remove anytime. Removing a language does not delete its translations; they’re soft-archived and restored if you re-add the language later.

Question translations

Read all translations for a question

curl https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel/translations \
  -H "Authorization: Bearer $FAQAPP_API_KEY"

Response:

{
  "data": [
    {
      "language": "es",
      "title": "¿Cómo cancelo mi suscripción?",
      "answer": "Abre Ajustes → Facturación → Cancelar suscripción...",
      "status": "published",
      "updatedAt": "2026-05-19T10:00:00Z"
    }
  ]
}

Create or update a translation

curl -X POST https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel/translations \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "language": "es",
    "title": "¿Cómo cancelo mi suscripción?",
    "answer": "Abre Ajustes → Facturación → Cancelar suscripción..."
  }'

POST is idempotent per (question, language) — calling it twice with different content updates the existing translation in place.

Patch (partial update)

curl -X PATCH https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel/translations/es \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "answer": "Updated Spanish answer." }'

Delete

curl -X DELETE https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel/translations/es \
  -H "Authorization: Bearer $FAQAPP_API_KEY"

Returns 204 No Content.

Required scope (create/update/delete): write.

Machine-translate

curl -X POST https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel/translations/ai \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "languages": ["es", "de", "fr"] }'

Runs all requested target languages in parallel. Returns the generated translations as status: draft so you can review before publishing. Re-running overwrites existing drafts; published translations are never touched.

Required scope: write.

Category translations

Same surface, scoped per category:

curl https://api.thefaq.app/api/v1/acme/categories/billing/translations \
  -H "Authorization: Bearer $FAQAPP_API_KEY"

Create + AI-translate via:

curl -X POST https://api.thefaq.app/api/v1/acme/categories/billing/translations \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -d '{ "language": "es", "name": "Facturación", "description": "..." }'

curl -X POST https://api.thefaq.app/api/v1/acme/categories/billing/translations/ai \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -d '{ "languages": ["es", "de"] }'

Reading translated content inline

To get a question or category in a specific language without a separate fetch, include Accept-Language:

curl https://api.thefaq.app/api/v1/acme/questions/how-do-i-cancel \
  -H "Authorization: Bearer $FAQAPP_API_KEY" \
  -H "Accept-Language: es"

The response replaces title + answer with the Spanish translation if one exists and is published, otherwise falls back to source. The x-faq-language-served response header tells you which language was actually returned.

Error codes

  • language_not_configured (400): target language not in your org’s targets list
  • translation_not_found (404): no translation exists for (question, language)
  • validation_failed (400): missing required field
  • ai_translation_failed (502): all AI providers errored
  • plan_limit_reached (402): translation features not available on Free plan