Посилання на 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).
Тіло запиту
| Поле | Тип | Обов’язкове | Опис |
|---|---|---|---|
content | string | Так | Непорожній рядок для перекладу. |
targets | string[] | Так | Непорожній масив дійсних кодів мов (макс. 36). |
format | string | Ні | Одне з plain, markdown, json, html. Якщо пропущено, формат автоматично визначається з content. |
source | string | Ні | Підказка про вихідну мову для моделі; необов’язково. |
model | string | Ні | 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. |
targets | string[] | Так | Ті ж правила, що й для /translate. |
source | string | Ні | Необов’язкова підказка про вихідну мову. |
model | string | Ні | 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-клієнта або проксі.
Тіло запиту
| Поле | Тип | Обов’язкове | Опис |
|---|---|---|---|
content | string | Так | Непорожній рядок для перекладу. |
targets | string[] | Так | Непорожній масив дійсних кодів мов (макс. 36). |
format | string | Ні | Одне з plain, markdown, json, html. Автоматично визначається, якщо пропущено. |
source | string | Ні | Підказка про вихідну мову; необов’язково. |
model | string | Ні | 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
}
status — pending (очікування працівника) або 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": "Людинозрозумілий опис"
}
| HTTP | error | Коли |
|---|---|---|
| 400 | invalid_request | Відсутні/некоректні поля тіла (наприклад, порожній content, неправильні targets) |
| 400 | invalid_format | format не в підтримуваному наборі |
| 400 | invalid_language | Невідомий код у targets |
| 401 | invalid_api_key | Відсутній/пошкоджений Authorization, невідомий ключ, відкликаний ключ |
| 403 | advanced_not_available | model: "advanced" на безкоштовному рівні |
| 429 | token_limit_reached | Перевищення місячного ліміту безкоштовного рівня (попередня перевірка) |
| 429 | rate_limit_reached | Ліміт RPM за хвилину (коли Redis увімкнено) |
| 500 | translation_error | Помилка моделі/мережі; можна повторити |
| 404 | not_found | GET /jobs/:id — завдання не існує або належить іншому користувачу |
| 500 | server_error | POST /jobs — не вдалося поставити в чергу; можна повторити |
GET /usage може повернути 500 з загальним повідомленням, якщо запит Supabase не вдався.
Підлеглі моделі (інформаційно)
API надає лише standard та advanced. Реальні ідентифікатори моделей OpenAI налаштовані у api/utils/modelRouter.js і не повертаються у відповідях API.