Full API reference: developer.universally.com carries the live specification for both the Translator API and the Platform API, with every field, status code and response example. This page covers what is worth knowing around it.
Every response uses the same envelope, so a client branches on the code field rather than on the HTTP status alone.
Response envelope
Every response, success or error, uses the same JSON envelope:
{
"success": false,
"data": null,
"message": "Invalid source URL format.",
"code": "TRANSLATION_INVALID_SOURCE_URL"
}
On error, success is false and data is null. Branch on the code field rather than the human-readable message, which may change.
Error codes
| Code | HTTP | Meaning |
|---|---|---|
API_KEY_MISSING |
401 | No X-API-Key header was provided. |
API_KEY_INVALID_FORMAT |
401 | The key is not a recognized format. |
API_KEY_MALFORMED |
401 | The key could not be parsed. |
API_KEY_INVALID |
401 | The key is well-formed but not recognized. |
API_KEY_PROJECT_INCOMPLETE |
500 | The site tied to this key is misconfigured. Contact support. |
PROJECT_NOT_FOUND |
404 | No site matches this key. |
PROJECT_IS_DELETED |
404 | The site has been deleted and is no longer accessible. |
TRANSLATION_INVALID_SOURCE_URL |
400 | sourceUrl is not a valid URL. |
TRANSLATION_SOURCE_URL_DOMAIN_MISMATCH |
403 | sourceUrl does not match your site’s domain. |
TRANSLATION_SAME_LANGUAGE |
400 | The target language equals the source language. |
TRANSLATION_TARGET_LANGUAGE_NOT_ALLOWED |
403 | The target language is not configured for your site, or you sent a region code where a variant code is required. |
TRANSLATION_NO_LANGUAGES_CONFIGURED |
400 | No target languages are configured for the site. |
TRANSLATION_SERVICE_UNAVAILABLE |
503 | The translation service is temporarily unavailable. Retry with backoff. |
TRANSLATION_SERVICE_FAILED |
500 | The translation service failed to process the request. |
NO_TRANSLATABLE_CONTENT |
400 | No translatable content was found in the HTML. |
VALIDATION_ERROR |
400 | The request body failed schema validation. |
INVALID_JSON |
400 | The request body is not valid JSON. |
DECOMPRESSION_ERROR |
400 | A gzip body could not be decompressed. |
REQUEST_TOO_LARGE |
413 | The request body exceeds 5 MB. |
NOT_FOUND |
404 | Unknown route. |
INTERNAL_SERVER_ERROR |
500 | Unexpected server error. Safe to retry with backoff. |
Request limits
| Limit | Value |
|---|---|
| Maximum request body | 5 MB |
| Maximum strings per request | 500 (strings endpoint) |
| Allowed methods | GET, POST, OPTIONS |
The 5 MB limit applies to the bytes you send, so a gzipped body is measured compressed. If it is exceeded you receive REQUEST_TOO_LARGE (413). For large pages or large string sets, compress the body or split the work across multiple requests.
Compressed request bodies
The Translator accepts gzip-compressed request bodies. Set the Content-Encoding header to gzip and send the compressed JSON; the body is decompressed before parsing. Because the size limit counts the bytes you send, compressing is what lets a document several times larger than 5 MB through.
Content-Type: application/json
Content-Encoding: gzip
If decompression fails, the response is DECOMPRESSION_ERROR (400).
Cross-origin requests
The Translator returns permissive CORS headers, allowing requests from any origin with the Content-Type, X-API-Key, and Content-Encoding headers. Even so, requests carry your API key and should be sent server-side. See Authentication.
Plan usage and partial translations
Translation draws down your plan's word total, shared across the HTML and strings endpoints.
Being over the limit is not an error. There is no status code for it: an over-limit workspace still gets a 200, with the shortfall reported in the metadata. The limit is checked once, when the request arrives, so a request that starts under the limit finishes everything it needs, even if that takes it past the total.
| Field | Meaning |
|---|---|
limitReached |
true when the workspace was already at or over its word total when the request arrived. |
skippedStrings |
The number of strings left untranslated because of that. |
When limitReached is true, treat the response as partial. Anything already translated is still returned from storage; anything that would have needed a new translation is not. On the HTML endpoint that text stays in the source language in the returned document. On the strings endpoint those keys are absent from the translations map, so fall back to your own source text for any key you do not get back. See Translate strings.
Raise the total with a word add-on or a larger plan. See Usage limits.
Retries
For transient errors (TRANSLATION_SERVICE_UNAVAILABLE at 503, or any 5xx), retry with exponential backoff. Translations are cached, so retried requests that previously partially succeeded reuse existing work and only translate what is still missing. Do not retry 4xx errors; they indicate a problem with the request that will not resolve on its own.