Translate documents
Upload a file, follow its job, review its sentences and download it translated, with its layout intact.
A document is translated in the background. You upload it, the API answers at once with a job, and you come back for the translated file, in the same format and with the same layout.
Formats
- Office: DOCX, XLSX, PPTX and their macro-enabled and template variants.
- OpenDocument: ODT, ODS, ODP, ODG and their templates.
- Web and text: HTML, XHTML, TXT, Markdown.
- Software: JSON, YAML, PO, Java properties.
A file can be up to 50 MB.
1. Upload
POST /v1/jobs takes a form (multipart/form-data) with the file and the two languages. The answer is 202 with the job, queued.
curl https://api.translaqe.com/v1/jobs \
-H "Authorization: Bearer $TRANSLAQE_API_KEY" \
-H "Idempotency-Key: contract-2026-10-12" \
-F "[email protected]" \
-F "source_lang=es" \
-F "target_lang=en" \
-F "glossary_ids=gl_3f9a1c2b7d5e4f60a1b2c3d4e5f60718" \
-F "webhook_url=https://example.com/hooks/translaqe"| Field | What it is for |
|---|---|
file |
The document. |
source_lang, target_lang |
The language it is in and the one you want. |
memory_ids, glossary_ids |
Memories and glossaries to translate with, separated by commas. |
project_id |
A project: its memories and glossaries are used, and the job is listed under it. |
webhook_url |
An HTTPS address to call when the job ends. |
notify_email |
An address to email when the job ends. |
allow_partial |
Deliver the file even if some sentence cannot be translated. |
Send an Idempotency-Key header with a value of your own. If the connection drops and you send the upload again with the same value, you get the same job back (200) instead of translating, and paying for, the file twice.
2. Wait for it
Ask for the job every few seconds until its status is final:
| Status | Meaning |
|---|---|
queued |
Waiting for its turn. |
running |
In progress: stage says where (extracting, translating, scoring, rebuilding) and progress how far. |
retrying |
It failed and will be tried again. |
succeeded |
Done: result has the numbers and the file is ready. |
failed |
It could not be done: error_code says why. |
cancelled |
You cancelled it. |
JOB=job_8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f
# Ask until it is over: succeeded, failed or cancelled.
while true; do
STATUS=$(curl -s "https://api.translaqe.com/v1/jobs/$JOB" \
-H "Authorization: Bearer $TRANSLAQE_API_KEY" | jq -r .status)
case "$STATUS" in succeeded|failed|cancelled) break ;; esac
sleep 5
done
# -OJ saves the file under the name the API gives it.
[ "$STATUS" = succeeded ] && curl -sOJ "https://api.translaqe.com/v1/jobs/$JOB/file" \
-H "Authorization: Bearer $TRANSLAQE_API_KEY"Or let us call you
With webhook_url, a POST is sent to your address when the job ends, well or badly:
POST /hooks/translaqe HTTP/1.1
Content-Type: application/json
User-Agent: TranslaQE-Webhook/1
X-TranslaQE-Event: job.succeeded
X-TranslaQE-Delivery: 5b0e…
{
"job_id": "job_8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f",
"status": "succeeded",
"error_code": null,
"sent_at": "2026-10-12T09:31:47+00:00"
}
The events are job.succeeded and job.failed, and for memories and glossaries resource.ready and resource.failed, which also carry resource_id and kind. A cancelled job sends nothing.
The notice carries no content and is not signed. Treat it as a hint: when it arrives, ask for the job with your key and act on what the API tells you.
3. Download
GET /v1/jobs/{job_id}/file returns the translated file. Its name comes in the Content-Disposition header. Before the job has succeeded the answer is 409 with the type job-not-ready.
result tells you how it went: the average score, how many sentences scored under 60 (low_score_segments) and how many needed a formatting mark fixed (mark_warnings).
When a sentence cannot be translated
If no model can translate some sentence, the job ends failed with error_code: "partial" and no file: a document with holes is not delivered behind your back. You have two ways out:
- Upload it with
allow_partial: true. The file is delivered with those sentences in the source language, andresult.failed_segmentssays how many. - Write the missing translations yourself (below) and build the file again.
Review and correct
Every sentence of the document is available at GET /v1/jobs/{job_id}/segments, with its source, its translation, its score and its state. Filter by band to go straight to the ones that need a look, correct them with PATCH, and ask for the file to be built again.
JOB=job_8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f
AUTH="Authorization: Bearer $TRANSLAQE_API_KEY"
# 1. The sentences that need another translation.
curl -s "https://api.translaqe.com/v1/jobs/$JOB/segments?band=rehacer" -H "$AUTH"
# 2. Correct one of them.
curl -s -X PATCH "https://api.translaqe.com/v1/jobs/$JOB/segments/12" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"target": "The rate in force at the time of the order will apply.", "state": "approved_translation"}'
# 3. Build the file again with the corrections.
curl -s -X POST "https://api.translaqe.com/v1/jobs/$JOB/rebuild" -H "$AUTH"
# 4. Keep what was approved in a memory, for next time.
curl -s -X POST "https://api.translaqe.com/v1/jobs/$JOB/review" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"memory_id": "tm_5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d"}'- A corrected sentence becomes a person's translation (
origin: "interactive") and loses its score. - The translation must keep the formatting marks of the source (
<g1>…</g1>,<x1/>): they are what puts bold, links and line breaks back in place. POST /v1/jobs/{job_id}/rebuilduses no characters: nothing is translated again.POST /v1/jobs/{job_id}/reviewsends to a memory what a person wrote or approved. The next document that repeats those sentences gets them from the memory.
Clean up
DELETE /v1/jobs/{job_id} deletes the job with its sentences and its files, the original and the translated one. A job that is queued or running has to be cancelled first, with POST /v1/jobs/{job_id}/cancel.