MTQE API (Machine Translation Quality Estimation)
The MTQE API scores the quality of translations from 0 to 100, without the need for a human reference, and explains the main issue found in each segment. It can judge them against your own translation memories and glossaries, and post-edit automatically the segments that fall short. See the introduction for what the service does.
To use the API, an API key provided by Pangeanic at the time of sale is required. To get one, contact our sales team at clients@pangeanic.com. Every example below can be copied and run as is: replace YOUR_API_KEY with your API key.
- Base URL:
https://api.pangeanic.com/mtqe/v2 - Authentication: send your key in the
X-API-Keyheader of every request. - Languages: codes like
en-usores-es. See supported languages. - Two ways to work: up to 50 segments per request, answered at once; or a job for up to 2,000.
- Interactive reference: https://api.pangeanic.com/mtqe/v2/docs
| What | Endpoint |
|---|---|
| Your usage | GET /usage |
| Supported languages | GET /languages |
| Score up to 50 segments, answered at once | POST /score-with-id-resources · POST /score-with-text-resources |
| Upload memories and glossaries | POST /resource/add_new · GET /resource/status · GET /resource/list |
| Score up to 2,000 segments as a job | POST /jobs/upload-file-job · POST /jobs/score-with-id-resources · POST /jobs/score-with-text-resources |
| Follow a job and get its result | GET /jobs/status-job · GET /jobs/get-job · GET /jobs/get-job-results · GET /jobs/list-jobs |
Supported Languages
Languages are sent as language-REGION codes (e.g. en-us, es-es). Any two supported languages can be combined as a language pair.
Notes:
- Codes are case-insensitive; the API returns them in lowercase.
- The bare language code is also accepted and maps to its default variant, for example
en→en-us,es→es-es,pt→pt-ptandzh→zh-cn. GET /languages(step 2) returns the same list.
Available languages (click to expand)
| Language | Code |
|---|---|
| Amharic | am-et |
| Arabic | ar-001 |
| Armenian | hy-am |
| Azerbaijani | az-az |
| Basque | eu-es |
| Bengali | bn-bd |
| Bulgarian | bg-bg |
| Burmese | my-mm |
| Catalan | ca-es |
| Chinese (Simplified) | zh-cn |
| Chinese (Traditional) | zh-tw |
| Croatian | hr-hr |
| Czech | cs-cz |
| Danish | da-dk |
| Dutch | nl-nl |
| Egyptian Arabic | ar-eg |
| English | en-us |
| English | en-gb |
| Estonian | et-ee |
| Filipino | fil-ph |
| Finnish | fi-fi |
| French | fr-fr |
| French | fr-ca |
| Galician | gl-es |
| Georgian | ka-ge |
| German | de-de |
| German | de-at |
| Greek | el-gr |
| Gujarati | gu-in |
| Hausa | ha-ng |
| Hebrew | he-il |
| Hindi | hi-in |
| Hungarian | hu-hu |
| Icelandic | is-is |
| Indonesian | id-id |
| Italian | it-it |
| Japanese | ja-jp |
| Kannada | kn-in |
| Korean | ko-kr |
| Latvian | lv-lv |
| Lithuanian | lt-lt |
| Macedonian | mk-mk |
| Malay | ms-my |
| Malayalam | ml-in |
| Marathi | mr-in |
| Mexican Spanish | es-mx |
| Norwegian | nb-no |
| Norwegian Nynorsk | nn-no |
| Occitan | oc-fr |
| Persian | fa-ir |
| Polish | pl-pl |
| Portuguese | pt-pt |
| Portuguese | pt-br |
| Punjabi | pa-in |
| Quechua | qu-pe |
| Romanian | ro-ro |
| Russian | ru-ru |
| Saudi Arabic | ar-sa |
| Serbian | sr-rs |
| Slovak | sk-sk |
| Slovenian | sl-si |
| Spanish | es-es |
| Swahili (Kenya) | sw-ke |
| Swahili (Tanzania) | sw-tz |
| Swedish | sv-se |
| Tamil | ta-in |
| Telugu | te-in |
| Thai | th-th |
| Turkish | tr-tr |
| Ukrainian | uk-ua |
| Urdu | ur-pk |
| Vietnamese | vi-vn |
| Zulu | zu-za |
Getting started
1. Check your key and your usage
GET /usage
URL: https://api.pangeanic.com/mtqe/v2/usage
Confirms that your key works and shows what you have used: characters for scoring, characters for automatic post-edition, your limit and what is left, per endpoint, and the memory and glossary files you have used in the period (files_used, files). It costs nothing.
{
"client": "acme",
"client_id": 7,
"is_admin": false,
"expires_at": null,
"char_quota": 1000000,
"source_chars_used": 24105,
"ape_source_chars_used": 770,
"total_source_chars_used": 24875,
"chars_remaining": 975125,
"files_used": 3,
"files": [
{
"id": "tm-5c1f0a9e2b7d",
"resource_type": "tm",
"filename": "memory_1.tmx",
"source_language": "en-us",
"target_language": "es-es",
"first_used_at": 1792050000.0,
"last_used_at": 1792310000.0,
"requests": 14
},
{
"id": "tm-9a3e7c51d2f4",
"resource_type": "tm",
"filename": "memory_2.tmx",
"source_language": "en-us",
"target_language": "es-es",
"first_used_at": 1792050000.0,
"last_used_at": 1792310000.0,
"requests": 14
},
{
"id": "gl-3b7e1d0c5a92",
"resource_type": "glossary",
"filename": "terms.tbx",
"source_language": "en-us",
"target_language": "es-es",
"first_used_at": 1792220000.0,
"last_used_at": 1792220000.0,
"requests": 1
}
],
"by_endpoint": [
{
"endpoint": "jobs/upload-file-job",
"requests": 2,
"segments": 300,
"source_chars": 19900,
"ape_segments": 12,
"ape_source_chars": 770
},
{
"endpoint": "score-with-id-resources",
"requests": 41,
"segments": 82,
"source_chars": 4205,
"ape_segments": 0,
"ape_source_chars": 0
}
]
}
Note
char_quota and chars_remaining are null when your key has no limit.
2. List the supported languages
GET /languages
URL: https://api.pangeanic.com/mtqe/v2/languages
The language codes you can use as source_language and target_language, with their names.
Scoring, answered at once
3. Basic score: no memories, no glossary, no post-edition
POST /score-with-id-resources
URL: https://api.pangeanic.com/mtqe/v2/score-with-id-resources
Send the segments with their language pair. Each one comes back with its score and the main issue found.
Request Parameters
| Parameter | Type | Location | Description |
|---|---|---|---|
X-API-Key |
string |
Header | Your API access key. |
segments |
array |
Body | 1 to 50 objects with source and target. |
source_language |
string |
Body | Language of every source (e.g. en-us). See supported languages. |
target_language |
string |
Body | Language of every target (e.g. es-es). See supported languages. |
tm_id |
array |
Body | Optional. Ids of your translation memories (step 4). |
glossary_id |
array |
Body | Optional. Ids of your glossaries (step 4). |
ape |
boolean |
Body | Optional. true to post-edit automatically the segments that fall short (step 7). Default false. |
ape_threshold |
integer |
Body | Optional. 0-100. Segments below it are post-edited. Default 90. |
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
segments = [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."},
]
body = {"segments": segments, "source_language": "en-us", "target_language": "es-es"}
r = requests.post(f"{BASE}/score-with-id-resources", headers=HEADERS, json=body)
r.raise_for_status()
for seg in r.json()["results"]:
print(seg["score"], seg["explanation"])
curl -X POST "https://api.pangeanic.com/mtqe/v2/score-with-id-resources" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."}
],
"source_language": "en-us",
"target_language": "es-es"
}'
{
"request_id": "5b2e9f7c1d3a4b6e8f0a2c4d6e8f1a3b",
"source_language": "en-us",
"target_language": "es-es",
"results": [
{
"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación.",
"source_chars": 53,
"score": 96.0,
"explanation": "",
"references": {
"tm": [],
"glossary": []
},
"error": null
},
{
"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo.",
"source_chars": 35,
"score": 22.5,
"explanation": "The negation was dropped: the target says the opposite of the source.",
"references": {
"tm": [],
"glossary": []
},
"error": null
}
]
}
4. Upload translation memories or glossaries
POST /resource/add_new
URL: https://api.pangeanic.com/mtqe/v2/resource/add_new
Upload your memories once and reuse them in every request. Each file gets an id; keep them. A glossary is uploaded the same way, with resource_type glossary.
Request Parameters
| Parameter | Type | Location | Description |
|---|---|---|---|
X-API-Key |
string |
Header | Your API access key. |
files |
file |
Form | One or more files, up to 20 MB each. Memories: .tmx, .csv, .tsv. Glossaries: .tbx, .csv, .tsv. |
resource_type |
string |
Form | tm or glossary. |
source_language |
string |
Form | Source language of the files (e.g. en-us). |
target_language |
string |
Form | Target language of the files (e.g. es-es). |
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
# uploading two TM
files = [("files", open("memory_1.tmx", "rb")),
("files", open("memory_2.tmx", "rb"))]
data = {"resource_type": "tm", "source_language": "en-us", "target_language": "es-es"}
r = requests.post(f"{BASE}/resource/add_new", headers=HEADERS, files=files, data=data)
r.raise_for_status()
ids = [res["id"] for res in r.json()["resources"]]
print(ids)
{
"resources": [
{
"id": "tm-5c1f0a9e2b7d",
"resource_type": "tm",
"filename": "memory_1.tmx",
"source_language": "en-us",
"target_language": "es-es",
"status": "SCHEDULED",
"error_code": null,
"error_message": null,
"failed_entries": 0,
"created_at": 1792735200.0,
"shared": null
},
{
"id": "tm-9a3e7c51d2f4",
"resource_type": "tm",
"filename": "memory_2.tmx",
"source_language": "en-us",
"target_language": "es-es",
"status": "SCHEDULED",
"error_code": null,
"error_message": null,
"failed_entries": 0,
"created_at": 1792735200.0,
"shared": null
}
]
}
Note
A memory only serves segments of its language pair. Upload each pair separately.
5. Wait until the memories are ready
GET /resource/status
URL: https://api.pangeanic.com/mtqe/v2/resource/status
A memory is indexed in the background after the upload. Check its status until it is SUCCESS; then it can be used. FAILED means it could not be used (see error_message).
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
import time
ids = ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"] # the ids from the upload
while True:
r = requests.get(f"{BASE}/resource/status", headers=HEADERS, params={"id": ids})
status = {res["id"]: res["status"] for res in r.json()["resources"]}
print(status)
if all(s in ("SUCCESS", "FAILED", "REJECTED") for s in status.values()):
break
time.sleep(10)
{
"resources": [
{
"id": "tm-5c1f0a9e2b7d",
"resource_type": "tm",
"filename": "memory_1.tmx",
"source_language": "en-us",
"target_language": "es-es",
"status": "SUCCESS",
"error_code": null,
"error_message": null,
"failed_entries": 0,
"created_at": 1792735200.0,
"shared": null
},
{
"id": "tm-9a3e7c51d2f4",
"resource_type": "tm",
"filename": "memory_2.tmx",
"source_language": "en-us",
"target_language": "es-es",
"status": "SUCCESS",
"error_code": null,
"error_message": null,
"failed_entries": 0,
"created_at": 1792735200.0,
"shared": null
}
]
}
6. Score with the two memories
POST /score-with-id-resources
URL: https://api.pangeanic.com/mtqe/v2/score-with-id-resources
The same request as the basic score, with the memory ids in tm_id (always a list). Each segment is judged against the most relevant entries of your memories, and they come back in references. Glossaries go in glossary_id the same way.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
segments = [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."},
]
body = {
"segments": segments,
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"],
}
r = requests.post(f"{BASE}/score-with-id-resources", headers=HEADERS, json=body)
r.raise_for_status()
for seg in r.json()["results"]:
print(seg["score"], seg["explanation"], len(seg["references"]["tm"]), "memory matches")
curl -X POST "https://api.pangeanic.com/mtqe/v2/score-with-id-resources" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."}
],
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"]
}'
{
"request_id": "8d1e4c2a9b7f4e3d8c6a5b4f3e2d1c0b",
"source_language": "en-us",
"target_language": "es-es",
"results": [
{
"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación.",
"source_chars": 53,
"score": 97.5,
"explanation": "",
"references": {
"tm": [
{
"source": "Please save your changes before closing the window.",
"target": "Guarde los cambios antes de cerrar la ventana.",
"score": 0.86
}
],
"glossary": []
},
"error": null
},
{
"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo.",
"source_chars": 35,
"score": 24.0,
"explanation": "The negation was dropped: the target says the opposite of the source.",
"references": {
"tm": [
{
"source": "He did not finish the report on time.",
"target": "No terminó el informe a tiempo.",
"score": 0.91
}
],
"glossary": []
},
"error": null
}
]
}
7. Score with the two memories and automatic post-edition
POST /score-with-id-resources
URL: https://api.pangeanic.com/mtqe/v2/score-with-id-resources
Add "ape": true. Every segment below ape_threshold (default 90) or with an issue is post-edited automatically and the post-edition is scored. hpe_needed says whether a person still has to review it. The post-edition is charged only when it fixes the segment.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
segments = [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."},
]
body = {
"segments": segments,
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"],
"ape": True,
"ape_threshold": 90, # optional, 0-100
}
r = requests.post(f"{BASE}/score-with-id-resources", headers=HEADERS, json=body)
r.raise_for_status()
for seg in r.json()["results"]:
if seg["ape_needed"]:
print(seg["score"], "→", seg["APE"]["score_ape"], seg["APE"]["target_ape"],
"· human review" if seg["hpe_needed"] else "")
curl -X POST "https://api.pangeanic.com/mtqe/v2/score-with-id-resources" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."}
],
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"],
"ape": true,
"ape_threshold": 90
}'
{
"request_id": "0f1e2d3c4b5a49687766554433221100",
"source_language": "en-us",
"target_language": "es-es",
"results": [
{
"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación.",
"source_chars": 53,
"score": 97.5,
"explanation": "",
"references": {
"tm": [
{
"source": "Please save your changes before closing the window.",
"target": "Guarde los cambios antes de cerrar la ventana.",
"score": 0.86
}
],
"glossary": []
},
"error": null,
"ape_needed": false,
"APE": {
"target_ape": "",
"score_ape": null,
"explanation_ape": ""
},
"hpe_needed": false,
"ape_source_chars": 0
},
{
"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo.",
"source_chars": 35,
"score": 24.0,
"explanation": "The negation was dropped: the target says the opposite of the source.",
"references": {
"tm": [
{
"source": "He did not finish the report on time.",
"target": "No terminó el informe a tiempo.",
"score": 0.91
}
],
"glossary": []
},
"error": null,
"ape_needed": true,
"APE": {
"target_ape": "Él no terminó el trabajo a tiempo.",
"score_ape": 98,
"explanation_ape": ""
},
"hpe_needed": false,
"ape_source_chars": 35
}
]
}
8. Score with references sent in the request
POST /score-with-text-resources
URL: https://api.pangeanic.com/mtqe/v2/score-with-text-resources
No upload needed: each segment carries its own memory entries (tm) and glossary terms (glossary), as source/target pairs, up to 20 of each. Useful when the references live in your own system. They are not charged, and the response does not repeat them. Takes ape like the previous steps.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
body = {
"segments": [{
"source": "Hold the start key for four seconds to restart the scanner.",
"target": "Mantenga la tecla de inicio cuatro segundos para reiniciar el escaner.",
"tm": [{"source": "Hold the start key for two seconds.",
"target": "Mantenga pulsada la tecla de inicio dos segundos."}],
"glossary": [{"source": "scanner", "target": "escáner"}],
}],
"source_language": "en-us",
"target_language": "es-es",
}
r = requests.post(f"{BASE}/score-with-text-resources", headers=HEADERS, json=body)
r.raise_for_status()
print(r.json()["results"][0])
curl -X POST "https://api.pangeanic.com/mtqe/v2/score-with-text-resources" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segments": [{
"source": "Hold the start key for four seconds to restart the scanner.",
"target": "Mantenga la tecla de inicio cuatro segundos para reiniciar el escaner.",
"tm": [{"source": "Hold the start key for two seconds.",
"target": "Mantenga pulsada la tecla de inicio dos segundos."}],
"glossary": [{"source": "scanner", "target": "escáner"}]
}],
"source_language": "en-us",
"target_language": "es-es"
}'
{
"request_id": "3f9c2b7e1a4d4e0c9b8a7f6e5d4c3b2a",
"source_language": "en-us",
"target_language": "es-es",
"results": [
{
"source": "Hold the start key for four seconds to restart the scanner.",
"target": "Mantenga la tecla de inicio cuatro segundos para reiniciar el escaner.",
"source_chars": 59,
"score": 74.0,
"explanation": "«escaner» does not follow the glossary: «escáner».",
"error": null
}
]
}
Many segments: jobs
9. Score a whole file
POST /jobs/upload-file-job
URL: https://api.pangeanic.com/mtqe/v2/jobs/upload-file-job
Upload an .xlsx or .csv with the columns source_language, target_language, source, target (one segment per row; pairs may be mixed). The job runs in the background; you get a job_id at once. Memory and glossary ids go one field per id; ape works as above. GET /jobs/template downloads an example file.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
files = {"file": open("segments.xlsx", "rb")}
data = [("tm_id", "tm-5c1f0a9e2b7d"), ("tm_id", "tm-9a3e7c51d2f4"), ("ape", "true")]
r = requests.post(f"{BASE}/jobs/upload-file-job", headers=HEADERS, files=files, data=data)
r.raise_for_status()
job_id = r.json()["job_id"]
print(job_id)
Note
The file is checked before the job is created: if something is wrong, the answer is a 422 listing every problem, and nothing is charged.
10. Score many segments sent as JSON
POST /jobs/score-with-id-resources · POST /jobs/score-with-text-resources
URL: https://api.pangeanic.com/mtqe/v2/jobs/score-with-id-resources · https://api.pangeanic.com/mtqe/v2/jobs/score-with-text-resources
The same body as the requests answered at once, with up to 2,000 segments. Use /jobs/score-with-id-resources with your memory and glossary ids, or /jobs/score-with-text-resources with the references in each segment.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
segments = [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."},
] # up to 2,000
body = {
"segments": segments,
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"],
"ape": True,
}
r = requests.post(f"{BASE}/jobs/score-with-id-resources", headers=HEADERS, json=body)
r.raise_for_status()
job_id = r.json()["job_id"]
print(job_id)
curl -X POST "https://api.pangeanic.com/mtqe/v2/jobs/score-with-id-resources" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"source": "Please save your work before closing the application.",
"target": "Guarde su trabajo antes de cerrar la aplicación."},
{"source": "He did not finish the work on time.",
"target": "Él terminó el trabajo a tiempo."}
],
"source_language": "en-us",
"target_language": "es-es",
"tm_id": ["tm-5c1f0a9e2b7d", "tm-9a3e7c51d2f4"],
"ape": true
}'
11. Follow a job and get its result
GET /jobs/status-job · GET /jobs/get-job · GET /jobs/get-job-results
URL: https://api.pangeanic.com/mtqe/v2/jobs/status-job · https://api.pangeanic.com/mtqe/v2/jobs/get-job · https://api.pangeanic.com/mtqe/v2/jobs/get-job-results
Ask for the status until it is done (or failed). Then download the result: an .xlsx for every job, and for jobs sent as JSON also the JSON, the same as the requests answered at once.
import requests
BASE = "https://api.pangeanic.com/mtqe/v2"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
import time
job_id = "a1b2c3d4e5f64789a0b1c2d3e4f5a6b7"
while True:
job = requests.get(f"{BASE}/jobs/status-job", headers=HEADERS,
params={"job_id": job_id}).json()
print(job["status"], job["processed"], "/", job["total"])
if job["status"] in ("done", "failed"):
break
time.sleep(5)
# The result as .xlsx (every job)
r = requests.get(f"{BASE}/jobs/get-job", headers=HEADERS, params={"job_id": job_id})
open("result.xlsx", "wb").write(r.content)
# The result as JSON (jobs sent as JSON)
result = requests.get(f"{BASE}/jobs/get-job-results", headers=HEADERS,
params={"job_id": job_id}).json()
# status
curl "https://api.pangeanic.com/mtqe/v2/jobs/status-job?job_id=a1b2c3d4e5f64789a0b1c2d3e4f5a6b7" \
-H "X-API-Key: YOUR_API_KEY"
# result as .xlsx (every job)
curl "https://api.pangeanic.com/mtqe/v2/jobs/get-job?job_id=a1b2c3d4e5f64789a0b1c2d3e4f5a6b7" \
-H "X-API-Key: YOUR_API_KEY" -o result.xlsx
# result as JSON (jobs sent as JSON)
curl "https://api.pangeanic.com/mtqe/v2/jobs/get-job-results?job_id=a1b2c3d4e5f64789a0b1c2d3e4f5a6b7" \
-H "X-API-Key: YOUR_API_KEY"
{
"job_id": "a1b2c3d4e5f64789a0b1c2d3e4f5a6b7",
"status": "done",
"kind": "file",
"filename": "segments.xlsx",
"total": 1200,
"processed": 1200,
"progress": 1.0,
"tm_ids": [
"tm-5c1f0a9e2b7d",
"tm-9a3e7c51d2f4"
],
"glossary_ids": [],
"error": null,
"created_at": 1792735200.0,
"updated_at": 1792735450.0,
"for_client_id": 7,
"ape": true,
"ape_threshold": 90,
"ape_segments": 95,
"ape_source_chars": 5910
}
Note
The example output is the status. The .xlsx has one row per segment with score, explanation and the references used, plus the post-edition columns when ape was on.
Score Interpretation
| Score Range | Estimated Quality | Recommended Action |
|---|---|---|
| 90 - 100 | Excellent | Direct publication or minimal review. |
| 70 - 89 | Good | Light human review (light MTPE). Check the explanation. |
| 40 - 69 | Medium / Low | Requires mandatory deep post-editing, or use ape. |
| < 40 | Very Low | Invalid translation or incoherent content. |
Disclaimer
This interpretation is solely a suggestion. The final decision on quality will always depend on the degree of strictness and the specific quality requirements (KPIs) required for each translation project.
Reference
The result of each segment
| Field | Meaning |
|---|---|
score |
Quality from 0 to 100. null if it could not be computed (see error). |
explanation |
The main issue found, in one sentence. Empty when there is none. |
references |
The translation memory matches (tm) and glossary terms (glossary) the segment was judged against. Their score is how relevant the entry is to the segment (0–1), not a quality score. Not returned when you send the references yourself (step 8). |
source_chars |
What the segment was charged: the characters of its source. |
error |
Why score is null, if it is. |
With automatic post-edition ("ape": true)
| Field | Meaning |
|---|---|
ape_needed |
The segment scored below ape_threshold (default 90) or had an issue, so it was post-edited. |
APE.target_ape |
The post-edited translation. Empty when it was not needed. |
APE.score_ape, APE.explanation_ape |
The score of the post-edited translation and any issue left in it. |
hpe_needed |
The post-edition still falls short: a person should review the segment. |
ape_source_chars |
What the post-edition was charged: the characters of the source again, only when it fixed the segment (hpe_needed: false). Otherwise 0. |
What is charged
| What is counted | When | |
|---|---|---|
| Scoring | The source of every segment | When the request (or job) is accepted |
| Automatic post-edition | The source again, only for the segments it fixed | When the request (or job) finishes |
| Files | Each memory or glossary (tm_id / glossary_id) used in the period, counted once however many requests use it: 3 files, then the same 3 = 3; those 3 plus a 4th = 4 |
When the request (or job) is accepted |
| Free | Uploading memories and glossaries, the references sent as text with a segment, and every query: usage, languages, status, results. |
Note
Your character limit covers scoring and post-edition together; files are counted apart. Step 1 shows how much you have used and how much is left. Results are not cached: sending the same segment again scores it, and charges it, again.
Limits and file formats
| Segments per request | 1 to 50 (more: use a job) |
| Segments per job | Up to 2,000 |
| Files | Up to 20 MB each |
| Translation memories | .tmx, .csv, .tsv |
| Glossaries | .tbx, .csv, .tsv |
| Job files | .xlsx or .csv; first row exactly source_language, target_language, source, target; one segment per row. GET /jobs/template downloads an example. |
| References sent with a segment | Up to 20 memory entries and 20 glossary terms per segment |
Other endpoints
| Endpoint | What it does |
|---|---|
GET /resource/list |
Your memories and glossaries, with their ids and status. |
GET /jobs/list-jobs |
Your recent jobs. |
GET /jobs/template |
An example job file (.xlsx) to fill in. |
POST /jobs/validate-job |
Checks a job file without creating a job or charging anything. |
GET /healthcheck |
Whether the service is up. No key needed. |
GET /docs |
The interactive API reference. |
Common Errors
The body of an error is {"detail": "…"} with the reason.
- 401 (Unauthorized): Missing, wrong, deactivated or expired API key.
- 404 (Not Found): A memory, glossary or job that does not exist for your key.
- 409 (Conflict): A job result asked for before the job is
done. - 413 (Payload Too Large): A file over the size limit.
- 422 (Unprocessable Entity): Something in the request is not valid: an unsupported language, a memory of another language pair, too many segments, a malformed file… The response says what.
- 429 (Too Many Requests): Character limit reached. Nothing was charged.
- 502, 503, 504: The service is busy or temporarily unavailable. Try again in a moment.