Skip to main content

Document Translation

Translate entire documents while preserving their original formatting. Upload a file, Langbly processes it in the background, and you download the translated result.

Supported Formats

FormatExtensionsNotes
Microsoft Word.docx, .docLegacy .doc outputs as .docx
Microsoft PowerPoint.pptx, .pptLegacy .ppt outputs as .pptx
Microsoft Excel.xlsx, .xlsLegacy .xls outputs as .xlsx
OpenDocument.odt, .ods, .odpText, Spreadsheet, Presentation
PDF.pdfText-based PDFs only (not scanned images)
Rich Text.rtfOutputs as .docx
HTML.html, .htm
Plain text.txt
Subtitles.srtPreserves timing codes
InDesign.idmlAdobe InDesign Markup Language

How It Works

  1. Upload your document with a target language
  2. Poll the job status until it completes
  3. Download the translated document

The entire process runs asynchronously. Most documents finish within 30 seconds to a few minutes depending on size.

Upload a Document

POST /v2/document/translate
Content-Type: multipart/form-data

Parameters

FieldTypeRequiredDescription
filefileYesThe document to translate (max 20 MB)
targetstringYesTarget language code (e.g. nl, de, fr)
sourcestringNoSource language code. Auto-detected if omitted.
formalitystringNoformal, informal, neutral, or auto
glossaryJSON stringNoInline glossary array: [{"source":"Hello","target":"Hallo"}]
glossaryIdstringNoID of a stored glossary to use. Inline glossary takes precedence.
instructionsstringNoCustom instructions for the translator (max 500 chars)

Example

curl -X POST https://api.langbly.com/v2/document/translate \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@report.docx" \
-F "target=nl" \
-F "formality=formal"

Response (202 Accepted)

{
"data": {
"jobId": "fb7451f7-b395-4e5c-8183-129d31745606",
"status": "queued"
}
}

Poll Job Status

GET /v2/document/:jobId
curl https://api.langbly.com/v2/document/fb7451f7-b395-4e5c-8183-129d31745606 \
-H "X-API-Key: YOUR_API_KEY"

Response

{
"data": {
"jobId": "fb7451f7-b395-4e5c-8183-129d31745606",
"status": "done",
"progress": 100,
"originalFilename": "report.docx",
"originalFormat": "docx",
"sourceLang": null,
"targetLang": "nl",
"charsExtracted": 12450,
"charsTranslated": 12450,
"segmentsTotal": 87,
"segmentsDone": 87,
"createdAt": "2026-02-26T10:00:00.000Z",
"completedAt": "2026-02-26T10:00:45.000Z",
"expiresAt": "2026-02-27T10:00:00.000Z"
}
}

Job Statuses

StatusDescription
queuedJob accepted, waiting to start
extractingExtracting text segments from the document
translatingTranslating segments (progress updates during this phase)
injectingInserting translations back into the document
doneComplete. Download the result.
errorFailed. Check errorMessage for details.

Download Result

GET /v2/document/:jobId/result

Returns the translated document as a binary download. Only available when status is done.

curl https://api.langbly.com/v2/document/fb7451f7-b395-4e5c-8183-129d31745606/result \
-H "X-API-Key: YOUR_API_KEY" \
-o report_nl.docx

The response includes:

  • Content-Type matching the output format
  • Content-Disposition with a suggested filename (e.g. report_nl.docx)

Code Examples

Python

import requests
import time

API_KEY = "your-api-key"
BASE = "https://api.langbly.com"

# 1. Upload
with open("report.docx", "rb") as f:
resp = requests.post(
f"{BASE}/v2/document/translate",
headers={"X-API-Key": API_KEY},
files={"file": f},
data={"target": "nl", "formality": "formal"},
)
job_id = resp.json()["data"]["jobId"]

# 2. Poll
while True:
status = requests.get(
f"{BASE}/v2/document/{job_id}",
headers={"X-API-Key": API_KEY},
).json()["data"]

if status["status"] in ("done", "error"):
break
time.sleep(3)

# 3. Download
if status["status"] == "done":
result = requests.get(
f"{BASE}/v2/document/{job_id}/result",
headers={"X-API-Key": API_KEY},
)
with open("report_nl.docx", "wb") as f:
f.write(result.content)

Node.js

const fs = require('fs');

const API_KEY = 'your-api-key';
const BASE = 'https://api.langbly.com';

async function translateDocument() {
// 1. Upload
const form = new FormData();
form.append('file', fs.createReadStream('report.docx'));
form.append('target', 'nl');

const upload = await fetch(`${BASE}/v2/document/translate`, {
method: 'POST',
headers: { 'X-API-Key': API_KEY },
body: form,
});
const { data: { jobId } } = await upload.json();

// 2. Poll
let status;
do {
await new Promise(r => setTimeout(r, 3000));
const poll = await fetch(`${BASE}/v2/document/${jobId}`, {
headers: { 'X-API-Key': API_KEY },
});
status = (await poll.json()).data;
} while (!['done', 'error'].includes(status.status));

// 3. Download
if (status.status === 'done') {
const result = await fetch(`${BASE}/v2/document/${jobId}/result`, {
headers: { 'X-API-Key': API_KEY },
});
const buffer = Buffer.from(await result.arrayBuffer());
fs.writeFileSync('report_nl.docx', buffer);
}
}

translateDocument();

Limits

LimitFree tierPaid plans
Max file size20 MB20 MB
Documents per month3Unlimited
Concurrent jobs33
Result availability24 hours24 hours
Min billable charsActual chars50,000 chars

Minimum charge

Paid plans are billed a minimum of 50,000 characters per document, even if the document contains fewer characters. This covers the overhead of document parsing and formatting preservation. Documents with more than 50,000 characters are billed at their actual character count.

Free tier accounts are not subject to the minimum charge.

Using Glossaries

You can use glossaries with document translation in two ways:

Inline glossary (passed with the request):

curl -X POST https://api.langbly.com/v2/document/translate \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@report.docx" \
-F "target=nl" \
-F 'glossary=[{"source":"Dashboard","target":"Overzichtspagina"}]'

Stored glossary (reference by ID):

curl -X POST https://api.langbly.com/v2/document/translate \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@report.docx" \
-F "target=nl" \
-F "glossaryId=your-glossary-id"

See the Glossary docs for more on creating and managing glossaries.

Custom Instructions

The instructions field lets you pass additional context to the translator. This can help with domain-specific content or style preferences.

curl -X POST https://api.langbly.com/v2/document/translate \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@legal-contract.docx" \
-F "target=nl" \
-F "instructions=This is a legal contract. Use formal legal Dutch terminology."

Instructions are limited to 500 characters.

Error Handling

If the job fails, the status response will include an errorMessage:

{
"data": {
"jobId": "...",
"status": "error",
"errorMessage": "Extract service returned 422: Unsupported file format"
}
}

Common errors:

ErrorCause
400 Unsupported file formatFile type not in the supported formats list
400 File too largeFile exceeds 20 MB limit
429 Too many active jobsYou have 3 concurrent jobs running
429 Monthly document limitFree tier: 3 documents per month
429 Free tier limit reachedNo characters remaining on free plan

Legacy Format Conversion

When you upload a legacy Office format (.doc, .ppt, .xls, .rtf), the translated output is in the modern format (.docx, .pptx, .xlsx). The original formatting is preserved during conversion.