Referensi API
Dokumen ini sesuai dengan perilaku aplikasi Express di api/app.js dan penangan rute di bawah api/routes/.
Batasan dan perilaku
| Item | Nilai |
|---|---|
| Ukuran body JSON | Hingga 2 MB (express.json({ limit: '2mb' })) |
| Target per permintaan | 1–36 kode bahasa |
| Item batch | 1–100 item per permintaan batch |
| Model | standard (default) atau advanced (hanya tingkat berbayar; lihat di bawah) |
Kuota token bulanan (tingkat gratis): Sebelum memanggil model, API memperkirakan token sekitar ceil(content_length / 4) × (number_of_targets + 1) dan, hanya untuk tingkat free, menolak permintaan dengan 429 / token_limit_reached jika perkiraan melebihi kuota bulanan yang tersisa (FREE_TIER_MONTHLY_TOKENS, default 100000). Tingkat berbayar tidak diblokir oleh pemeriksaan awal ini di enforceTokenCap; penggunaan tetap dicatat.
Batas laju: Ketika Upstash Redis dikonfigurasi (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, dan URL tidak mengandung placeholder your-instance), batas per menit berlaku berdasarkan tingkat: gratis 5, starter 30, growth 60, scale 120, enterprise tanpa batas. Saat batas tercapai, respons adalah 429 dengan error: "rate_limit_reached". Jika Redis tidak dikonfigurasi, pembatasan laju dilewati (lihat rateLimit.js).
Respons yang berhasil dengan pembatasan laju dapat menyertakan X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
GET /health
Tanpa autentikasi.
Respons 200
{
"status": "ok",
"timestamp": "2025-03-23T12:00:00.000Z"
}
GET /languages
Tanpa autentikasi.
Mengembalikan daftar kanonik bahasa yang didukung (kode, nama tampilan, flag RTL). Ada 36 entri; kode adalah satu-satunya nilai yang diterima di targets pada endpoint terjemahan.
Respons 200
{
"languages": [
{ "code": "en", "name": "English", "rtl": false },
{ "code": "ar", "name": "Arabic", "rtl": true }
]
}
Sumber: api/utils/languages.js.
POST /translate
Memerlukan Authorization: Bearer <api_key>.
Menerjemahkan satu string content ke setiap bahasa yang tercantum dalam targets. Model mengembalikan objek JSON tunggal yang kuncinya adalah tepat kode bahasa yang diminta dan nilainya adalah string terjemahan (lihat formatPrompts.js).
Body permintaan
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
content | string | Ya | String tidak kosong untuk diterjemahkan. |
targets | string[] | Ya | Array tidak kosong dari kode bahasa yang valid (maks 36). |
format | string | Tidak | Salah satu dari plain, markdown, json, html. Jika dihilangkan, format terdeteksi otomatis dari content. |
source | string | Tidak | Petunjuk bahasa sumber untuk model; opsional. |
model | string | Tidak | standard (default) atau advanced. advanced memerlukan tingkat berbayar (403 pada gratis). |
Respons 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 dan detection_confidence hanya muncul ketika format dihilangkan dan deteksi otomatis dijalankan.
Contoh (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"]
}'
Contoh (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
Memerlukan Authorization: Bearer <api_key>.
Memproses setiap item secara berurutan (satu panggilan model per item). Jika ada item yang gagal, API mengembalikan 500 dan tidak mengembalikan hasil parsial untuk permintaan itu.
Body permintaan
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
items | array | Ya | Setiap elemen: id (string), content (string), format opsional. |
targets | string[] | Ya | Aturan sama seperti /translate. |
source | string | Tidak | Petunjuk bahasa sumber opsional. |
model | string | Tidak | standard atau advanced (aturan sama seperti /translate). |
Respons 200
{
"results": [
{ "id": "welcome", "translations": { "fr": "...", "de": "..." } },
{ "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
],
"usage": {
"total_tokens": 900,
"input_tokens": 400,
"output_tokens": 500,
"model": "standard"
}
}
Contoh
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
Memerlukan Authorization: Bearer <api_key>.
Mengantri pekerjaan terjemahan dan langsung mengembalikan job_id. Terjemahan berjalan di latar belakang — tanpa risiko timeout HTTP terlepas dari ukuran konten. Poll GET /jobs/:id untuk hasil.
Gunakan endpoint ini sebagai pengganti POST /translate saat menerjemahkan dokumen besar (Markdown panjang, banyak bahasa target) di mana durasi permintaan mungkin melebihi timeout klien HTTP atau proxy Anda.
Body permintaan
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
content | string | Ya | String tidak kosong untuk diterjemahkan. |
targets | string[] | Ya | Array tidak kosong dari kode bahasa yang valid (maks 36). |
format | string | Tidak | Salah satu dari plain, markdown, json, html. Terdeteksi otomatis jika dihilangkan. |
source | string | Tidak | Petunjuk bahasa sumber; opsional. |
model | string | Tidak | standard (default) atau advanced. |
Respons 202
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z"
}
GET /jobs/:id
Memerlukan Authorization: Bearer <api_key>.
Melakukan polling status pekerjaan yang dikirim melalui POST /jobs. Poll setiap 5–10 detik. Pekerjaan dimiliki oleh pengguna yang mengirim — pengguna lain menerima 404.
Respons (pending / processing)
{
"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 adalah pending (menunggu pekerja) atau processing (pekerja telah mengklaimnya). queue_position (berbasis 1) adalah berapa banyak pekerjaan pending atau processing yang dibuat sebelum ini — gunakan untuk UI progres. Dihilangkan saat query hitungan gagal.
Respons (completed)
{
"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"
}
}
Respons (failed)
{
"job_id": "a1b2c3d4-...",
"status": "failed",
"error": "Model returned invalid JSON"
}
Contoh (JavaScript)
const API = 'https://api.usepolylingo.com/v1'
const headers = {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
}
// 1. Kirim
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. Poll
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) }
// Opsional: tampilkan progres (queue_position berbasis 1, dihilangkan saat tidak dalam antrean)
if (job.queue_position != null) console.log(`Queue position: ${job.queue_position}`)
}
GET /usage
Memerlukan Authorization: Bearer <api_key> (pencarian kunci standar — bukan jalur bypass internal saja).
Mengembalikan penggunaan token untuk bulan kalender saat ini untuk pengguna yang diautentikasi.
Respons 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 dan tokens_remaining adalah null untuk enterprise (kuota tak terbatas dalam pelaporan).
Format konten
Nilai format yang didukung: plain, markdown, json, html.
| Format | Dipertahankan | Diterjemahkan |
|---|---|---|
plain | Pemisah baris / paragraf | Semua teks yang terlihat |
markdown | Sintaks, tautan (URL tidak berubah), kode fenced (verbatim) | Prosa dan teks tautan |
json | Kunci, struktur, tipe non-string | Hanya nilai string |
html | Tag dan atribut | Node teks dan atribut yang sesuai (lihat prompt) |
RTL dan arah di aplikasi Anda
Untuk output plain dan markdown, API hanya mengembalikan teks terjemahan — tidak menambahkan dir="rtl" atau elemen pembungkus. Atur arah teks di UI Anda (CSS direction, atribut dir elemen induk, atau tata letak i18n framework Anda) saat menampilkan bahasa Arab, Ibrani, atau Persia.
Untuk format html, markup terjemahan dapat menyertakan dir="rtl" di tempat yang sesuai untuk target RTL; lihat formatPrompts.js dan pengujian HTML di scripts/test-translation.js.
Respons kesalahan
Kesalahan berupa JSON bila memungkinkan:
{
"error": "invalid_request",
"message": "Detail yang dapat dibaca manusia"
}
| HTTP | error | Kapan |
|---|---|---|
| 400 | invalid_request | Field body hilang/tidak valid (misal content kosong, targets buruk) |
| 400 | invalid_format | format tidak dalam set yang didukung |
| 400 | invalid_language | Kode tidak dikenal di targets |
| 401 | invalid_api_key | Authorization hilang/salah, kunci tidak dikenal, kunci dicabut |
| 403 | advanced_not_available | model: "advanced" di tingkat gratis |
| 429 | token_limit_reached | Batas bulanan tingkat gratis terlampaui (pemeriksaan awal) |
| 429 | rate_limit_reached | Batas RPM per menit (saat Redis diaktifkan) |
| 500 | translation_error | Kegagalan model/jaringan; aman untuk mencoba ulang |
| 404 | not_found | GET /jobs/:id — pekerjaan tidak ada atau milik pengguna lain |
| 500 | server_error | POST /jobs — gagal mengantri; aman untuk mencoba ulang |
GET /usage dapat mengembalikan 500 dengan pesan umum jika query Supabase gagal.
Model dasar (informasi)
API hanya mengekspos standard dan advanced. ID model OpenAI sebenarnya dikonfigurasi di api/utils/modelRouter.js dan tidak dikembalikan dalam respons API.