Référence API

Référence complète pour chaque point de terminaison, forme de requête et de réponse, code d'erreur et limite de débit.

Limites et comportement

ÉlémentValeur
Taille du corps JSONJusqu'à 2 Mo (express.json({ limit: '2mb' }))
Cibles par requête1–50 codes de langue
Éléments par lot1–100 éléments par requête batch
Modèlesstandard (par défaut) ou advanced (uniquement niveaux payants ; voir ci-dessous)

Allocation mensuelle de jetons (niveau gratuit) : Avant d'appeler le modèle, l'API estime les jetons approximativement comme ceil(content_length / 4) × (number_of_targets + 1) et, uniquement pour le niveau free, rejette la requête avec 429 / token_limit_reached si l'estimation dépasserait la subvention mensuelle restante (par défaut 100000). Les niveaux payants ne sont pas bloqués par cette pré-vérification ; l'utilisation est toujours enregistrée.

Limites de débit : Lorsque Redis est configuré, des limites par minute s'appliquent selon le niveau : free 5, starter 30, growth 60, scale 120, enterprise illimité. En cas de dépassement, la réponse est 429 avec error: "rate_limit_reached". Si Redis n'est pas configuré, la limitation de débit est ignorée.

Les réponses réussies avec limitation de débit peuvent inclure X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.


GET /health

Pas d'authentification.

Réponse 200

{
  "status": "ok",
  "timestamp": "2025-03-23T12:00:00.000Z"
}

GET /languages

Pas d'authentification.

Renvoie la liste canonique des langues supportées (code, nom affiché, indicateur RTL). Il y a 43 entrées — 36 langues de base et 7 variantes régionales. Les variantes régionales utilisent des sous-tags régionaux BCP-47 (ex. fr-CA, pt-BR, es-MX). Les codes de ce point de terminaison sont les seules valeurs acceptées dans targets sur les points de terminaison de traduction.

Réponse 200

{
  "languages": [
    { "code": "en", "name": "English", "rtl": false },
    { "code": "ar", "name": "Arabic", "rtl": true }
  ]
}

La liste en direct est également disponible via GET /languages — voir ci-dessous.


POST /translate

Nécessite Authorization: Bearer <api_key>.

Traduit une seule chaîne content dans chaque langue listée dans targets. La réponse est un objet JSON unique dont les clés sont exactement les codes de langue demandés et dont les valeurs sont les chaînes traduites.

Corps de la requête

ChampTypeObligatoireDescription
contentstringOuiChaîne non vide à traduire.
targetsstring[]OuiTableau non vide de codes de langue valides (max 36).
formatstringNonL'un des plain, markdown, json, html. Si omis, le format est auto-détecté à partir de content.
sourcestringNonIndice de langue source pour le modèle ; optionnel.
modelstringNonstandard (par défaut) ou advanced. advanced nécessite un niveau payant (403 sur free).

Réponse 200

{
  "translations": {
    "es": "...",
    "fr": "..."
  },
  "usage": {
    "input_tokens": 120,
    "output_tokens": 340,
    "total_tokens": 460,
    "model": "standard",
    "detected_format": "markdown",
    "detection_confidence": 0.95
  }
}

detected_format et detection_confidence apparaissent uniquement lorsque format a été omis et que la détection automatique a été effectuée.

Exemple (cURL)

curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
  -H "Authorization: Bearer $POLYLINGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "{\"title\":\"Hello\"}",
    "format": "json",
    "targets": ["fr", "de"]
  }'

Exemple (Python 3)

pip install requests
import os, requests

url = "https://api.usepolylingo.com/v1/translate"
headers = {
    "Authorization": f"Bearer {os.environ['POLYLINGO_API_KEY']}",
    "Content-Type": "application/json",
}
r = requests.post(url, json={
    "content": "<p>Hello <strong>world</strong></p>",
    "format": "html",
    "targets": ["es"],
}, timeout=120)
r.raise_for_status()
print(r.json()["translations"]["es"])

POST /translate/batch

Nécessite Authorization: Bearer <api_key>.

Traite chaque élément séquentiellement (un appel modèle par élément). Si un élément échoue, l'API renvoie 500 et ne retourne pas de résultats partiels pour cette requête.

Corps de la requête

ChampTypeObligatoireDescription
itemsarrayOuiChaque élément : id (string), content (string), format optionnel.
targetsstring[]OuiMême règles que /translate.
sourcestringNonIndice de langue source optionnel.
modelstringNonstandard ou advanced (mêmes règles que /translate).

Réponse 200

{
  "results": [
    { "id": "welcome", "translations": { "fr": "...", "de": "..." } },
    { "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
  ],
  "usage": {
    "total_tokens": 900,
    "input_tokens": 400,
    "output_tokens": 500,
    "model": "standard"
  }
}

Exemple

curl -sS -X POST "https://api.usepolylingo.com/v1/translate/batch" \
  -H "Authorization: Bearer $POLYLINGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "id": "a", "content": "Hello", "format": "plain" },
      { "id": "b", "content": "## Title", "format": "markdown" }
    ],
    "targets": ["es", "it"]
  }'

POST /jobs

Nécessite Authorization: Bearer <api_key>.

Place un travail de traduction en file d'attente et répond immédiatement avec un job_id. La traduction s'exécute en arrière-plan — aucun risque de timeout HTTP quelle que soit la taille du contenu. Interrogez GET /jobs/:id pour le résultat.

Utilisez ce point de terminaison au lieu de POST /translate lors de la traduction de documents volumineux (Markdown long, nombreuses langues cibles) où la durée de la requête pourrait dépasser le timeout de votre client HTTP ou proxy.

Corps de la requête

ChampTypeObligatoireDescription
contentstringOuiChaîne non vide à traduire.
targetsstring[]OuiTableau non vide de codes de langue valides (max 36).
formatstringNonL'un des plain, markdown, json, html. Détecté automatiquement si omis.
sourcestringNonIndice de langue source ; optionnel.
modelstringNonstandard (par défaut) ou advanced.

Réponse 202

{
  "job_id": "a1b2c3d4-...",
  "status": "pending",
  "created_at": "2025-03-23T12:00:00.000Z"
}

GET /jobs/:id

Nécessite Authorization: Bearer <api_key>.

Interroge le statut d'un travail soumis via POST /jobs. Interrogez toutes les 5–10 secondes. Les travaux appartiennent à l'utilisateur qui les a soumis — les autres utilisateurs reçoivent 404.

Réponse (en attente / en traitement)

{
  "job_id": "a1b2c3d4-...",
  "status": "pending",
  "created_at": "2025-03-23T12:00:00.000Z",
  "updated_at": "2025-03-23T12:00:00.000Z",
  "completed_at": null,
  "queue_position": 3
}

status est pending (en attente d'un worker) ou processing (worker l'a pris). queue_position (base 1) indique combien de travaux en attente ou en traitement ont été créés strictement avant celui-ci — utilisez-le pour l'interface utilisateur de progression. Omit si la requête de comptage échoue.

Réponse (terminé)

{
  "job_id": "a1b2c3d4-...",
  "status": "completed",
  "created_at": "2025-03-23T12:00:00.000Z",
  "updated_at": "2025-03-23T12:00:02.000Z",
  "completed_at": "2025-03-23T12:00:02.000Z",
  "translations": {
    "es": "...",
    "fr": "..."
  },
  "usage": {
    "input_tokens": 120,
    "output_tokens": 340,
    "total_tokens": 460,
    "model": "standard"
  }
}

Réponse (échoué)

{
  "job_id": "a1b2c3d4-...",
  "status": "failed",
  "error": "Model returned invalid JSON"
}

Exemple (JavaScript)

const API = 'https://api.usepolylingo.com/v1'
const headers = {
  'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
  'Content-Type': 'application/json',
}

// 1. Soumettre
const submit = await fetch(`${API}/jobs`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ content: longMarkdown, format: 'markdown', targets: ['de', 'fr'] }),
})
const { job_id } = await submit.json()

// 2. Interroger
while (true) {
  await new Promise(r => setTimeout(r, 10_000))
  const poll = await fetch(`${API}/jobs/${job_id}`, { headers })
  const job = await poll.json()
  if (job.status === 'completed') { console.log(job.translations); break }
  if (job.status === 'failed')    { throw new Error(job.error) }
  // Optionnel : afficher la progression (queue_position est basé sur 1, omis si non en file)
  if (job.queue_position != null) console.log(`Position dans la file : ${job.queue_position}`)
}

GET /usage

Nécessite Authorization: Bearer <api_key> (recherche de clé standard — pas le chemin interne de contournement).

Renvoie l'utilisation des jetons pour le mois calendaire en cours pour l'utilisateur authentifié.

Réponse 200

{
  "period_start": "2025-03-01T00:00:00.000Z",
  "period_end": "2025-03-31T23:59:59.000Z",
  "tokens_used": 12000,
  "tokens_included": 100000,
  "tokens_remaining": 88000,
  "overage_tokens": 0,
  "tier": "free"
}

tokens_included et tokens_remaining sont null pour enterprise (allocation illimitée dans les rapports).


Formats de contenu

Valeurs format supportées : plain, markdown, json, html.

FormatConservéTraduit
plainSauts de ligne / paragraphesTout le texte visible
markdownSyntaxe, liens (URL inchangée), code délimité (littéral)Prose et texte des liens
jsonClés, structure, types non chaîneValeurs chaînes uniquement
htmlBalises et attributsNœuds de texte et attributs appropriés (voir prompts)

RTL et direction dans votre application

Pour les sorties plain et markdown, l'API renvoie uniquement le texte traduit — elle n'ajoute pas dir="rtl" ni d'éléments enveloppants. Définissez la direction du texte dans votre UI (CSS direction, attribut dir d'un élément parent ou mise en page i18n de votre framework) lors de l'affichage de l'arabe, de l'hébreu ou du persan.

Pour le format html, le balisage traduit peut inclure dir="rtl" là où c'est approprié pour les cibles RTL.


Réponses d'erreur

Les erreurs sont en JSON quand c'est possible :

{
  "error": "invalid_request",
  "message": "Détail lisible par un humain"
}
HTTPerrorQuand
400invalid_requestChamps du corps manquants/invalides (ex. content vide, targets incorrects)
400invalid_formatformat non dans l'ensemble supporté
400invalid_languageCode inconnu dans targets
401invalid_api_keyAuthorization manquant/malformé, clé inconnue, clé révoquée
403advanced_not_availablemodel: "advanced" sur niveau gratuit
429token_limit_reachedPlafond mensuel du niveau gratuit dépassé (pré-vérification)
429rate_limit_reachedLimite RPM par minute (quand Redis activé)
500translation_errorÉchec modèle/réseau ; sécurisé pour réessayer
404not_foundGET /jobs/:id — travail inexistant ou appartenant à un autre utilisateur
500server_errorPOST /jobs — échec de mise en file ; sécurisée pour réessayer

GET /usage peut retourner 500 avec un message générique si la requête Supabase échoue.

Référence API | PolyLingo | PolyLingo