Посилання на API

Цей документ відповідає поведінці Express-додатку у файлі api/app.js та обробникам маршрутів у папці api/routes/.

Обмеження та поведінка

ЕлементЗначення
Розмір JSON-телаДо 2 МБ (express.json({ limit: '2mb' }))
Цілі на запит1–36 кодів мов
Елементи пакету1–100 елементів на пакетний запит
Моделіstandard (за замовчуванням) або advanced (тільки платні рівні; див. нижче)

Місячна квота токенів (безкоштовний рівень): Перед викликом моделі API приблизно оцінює токени як ceil(content_length / 4) × (number_of_targets + 1) і для free рівня відхиляє запит з кодом 429 / token_limit_reached, якщо оцінка перевищує залишок місячної квоти (FREE_TIER_MONTHLY_TOKENS, за замовчуванням 100000). Платні рівні не блокуються цією перевіркою у enforceTokenCap; використання все одно логуються.

Обмеження швидкості: Коли налаштовано Upstash Redis (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, і URL не містить заповнювач your-instance), застосовуються обмеження за хвилину за рівнями: безкоштовний 5, початковий 30, зростання 60, масштаб 120, корпоративний без обмежень. При досягненні ліміту відповідь має код 429 з error: "rate_limit_reached". Якщо Redis не налаштовано, обмеження швидкості пропускаються (див. rateLimit.js).

Успішні відповіді з обмеженням швидкості можуть містити заголовки X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.


GET /health

Без автентифікації.

Відповідь 200

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

GET /languages

Без автентифікації.

Повертає канонічний список підтримуваних мов (код, відображуване ім'я, прапорець RTL). Всього 36 записів; коди — єдині прийнятні значення у targets на кінцевих точках перекладу.

Відповідь 200

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

Джерело: api/utils/languages.js.


POST /translate

Потрібен заголовок Authorization: Bearer <api_key>.

Перекладає один рядок content на всі мови, вказані у targets. Модель повертає один JSON-об'єкт, ключі якого — точно запитані коди мов, а значення — перекладені рядки (див. formatPrompts.js).

Тіло запиту

ПолеТипОбов’язковеОпис
contentstringТакНепорожній рядок для перекладу.
targetsstring[]ТакНепорожній масив дійсних кодів мов (макс. 36).
formatstringНіОдне з plain, markdown, json, html. Якщо пропущено, формат автоматично визначається з content.
sourcestringНіПідказка про вихідну мову для моделі; необов’язково.
modelstringНіstandard (за замовчуванням) або advanced. advanced вимагає платний рівень (403 для безкоштовного).

Відповідь 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 і detection_confidence з’являються лише коли format пропущено і запущено авто-визначення.

Приклад (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"]
  }'

Приклад (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

Потрібен заголовок Authorization: Bearer <api_key>.

Обробляє кожен елемент послідовно (один виклик моделі на елемент). Якщо будь-який елемент не вдається, API повертає 500 і не повертає часткових результатів для цього запиту.

Тіло запиту

ПолеТипОбов’язковеОпис
itemsмасивТакКожен елемент: id (рядок), content (рядок), необов’язковий format.
targetsstring[]ТакТі ж правила, що й для /translate.
sourcestringНіНеобов’язкова підказка про вихідну мову.
modelstringНіstandard або advanced (ті ж правила, що й для /translate).

Відповідь 200

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

Приклад

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

Потрібен заголовок Authorization: Bearer <api_key>.

Додає завдання перекладу в чергу і негайно повертає job_id. Переклад виконується у фоновому режимі — ризик тайм-ауту HTTP відсутній незалежно від розміру вмісту. Для отримання результату опитуйте GET /jobs/:id.

Використовуйте цю кінцеву точку замість POST /translate при перекладі великих документів (довгий Markdown, багато цільових мов), де тривалість запиту може перевищити тайм-аут вашого HTTP-клієнта або проксі.

Тіло запиту

ПолеТипОбов’язковеОпис
contentstringТакНепорожній рядок для перекладу.
targetsstring[]ТакНепорожній масив дійсних кодів мов (макс. 36).
formatstringНіОдне з plain, markdown, json, html. Автоматично визначається, якщо пропущено.
sourcestringНіПідказка про вихідну мову; необов’язково.
modelstringНіstandard (за замовчуванням) або advanced.

Відповідь 202

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

GET /jobs/:id

Потрібен заголовок Authorization: Bearer <api_key>.

Опитує статус завдання, надісланого через POST /jobs. Опитуйте кожні 5–10 секунд. Завдання належать користувачу, який їх надіслав — інші користувачі отримують 404.

Відповідь (очікування / обробка)

{
  "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
}

statuspending (очікування працівника) або processing (працівник взяв завдання). queue_position (починається з 1) — скільки завдань у стані очікування або обробки було створено строго раніше за це — використовується для інтерфейсу прогресу. Пропускається, якщо запит на підрахунок не вдався.

Відповідь (завершено)

{
  "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"
  }
}

Відповідь (помилка)

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

Приклад (JavaScript)

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

// 1. Надіслати
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. Опитування
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) }
  // Необов’язково: показати прогрес (queue_position починається з 1, пропускається, якщо не в черзі)
  if (job.queue_position != null) console.log(`Позиція в черзі: ${job.queue_position}`)
}

GET /usage

Потрібен заголовок Authorization: Bearer <api_key> (стандартний пошук ключа — не внутрішній шлях обходу).

Повертає використання токенів за поточний календарний місяць для автентифікованого користувача.

Відповідь 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 і tokens_remaining дорівнюють null для enterprise (необмежена квота у звітах).


Формати вмісту

Підтримувані значення format: plain, markdown, json, html.

ФорматЗбереженоПерекладено
plainПереноси рядків / абзациВесь видимий текст
markdownСинтаксис, посилання (URL без змін), блоки коду (дослівно)Проза і текст посилань
jsonКлючі, структура, не рядкові типиТільки рядкові значення
htmlТеги та атрибутиТекстові вузли та відповідні атрибути (див. підказки)

RTL та напрямок у вашому додатку

Для виводу plain і markdown API повертає лише перекладений текст — не додає dir="rtl" або обгорткові елементи. Встановлюйте напрямок тексту у вашому UI (CSS direction, атрибут dir батьківського елемента або i18n-розмітка вашого фреймворку) при відображенні арабської, івриту або перської.

Для формату html перекладена розмітка може містити dir="rtl" там, де це доречно для RTL-цілей; див. formatPrompts.js та HTML-тести у scripts/test-translation.js.


Відповіді з помилками

Помилки у форматі JSON, якщо можливо:

{
  "error": "invalid_request",
  "message": "Людинозрозумілий опис"
}
HTTPerrorКоли
400invalid_requestВідсутні/некоректні поля тіла (наприклад, порожній content, неправильні targets)
400invalid_formatformat не в підтримуваному наборі
400invalid_languageНевідомий код у targets
401invalid_api_keyВідсутній/пошкоджений Authorization, невідомий ключ, відкликаний ключ
403advanced_not_availablemodel: "advanced" на безкоштовному рівні
429token_limit_reachedПеревищення місячного ліміту безкоштовного рівня (попередня перевірка)
429rate_limit_reachedЛіміт RPM за хвилину (коли Redis увімкнено)
500translation_errorПомилка моделі/мережі; можна повторити
404not_foundGET /jobs/:id — завдання не існує або належить іншому користувачу
500server_errorPOST /jobs — не вдалося поставити в чергу; можна повторити

GET /usage може повернути 500 з загальним повідомленням, якщо запит Supabase не вдався.


Підлеглі моделі (інформаційно)

API надає лише standard та advanced. Реальні ідентифікатори моделей OpenAI налаштовані у api/utils/modelRouter.js і не повертаються у відповідях API.

Довідник API | PolyLingo | PolyLingo