Use this API to send content for translation, track its progress, and retrieve the translations in all target languages.
This API accepts JSON-structured content, preserving the original structure and keys. It translates only text values, leaving numbers, booleans, nulls, and other non-text values unchanged.
API Quick Links
Create Content Translations
Creates a new translation job from JSON-structured data.
The endpoint preserves your content’s original hierarchy of keys and arrays, translating only text values while leaving numbers, booleans, nulls, and other non-text values unchanged.
It is especially useful for:
- Content management – Localizing dynamic content structured in JSON
- Configuration files – Translating user-facing strings in config data
- API responses – Translating structured response payloads
- Documentation – Localizing hierarchical help content or guides
HTTP Request
POST https://app.ptc.wpml.org/api/v1/content_translationParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
data | object | Yes | The JSON-structured data to translate. It can include nested objects, arrays, and string values. |
name | string | No | A human-readable name for the translation job. If omitted, one is generated automatically. |
callback_url | string | No | The URL that receives webhook notifications when the translation is complete. |
target_languages | array[string] | No | The array of ISO codes for target languages. If omitted, translations are created for all project-configured languages. See the Available Target Languages API for more information. |
Request Body Example
{
"data": {
"app": {
"title": "My Application",
"navigation": {
"home": "Home",
"about": "About Us",
"contact": "Contact"
},
"buttons": {
"save": "Save",
"cancel": "Cancel",
"submit": "Submit"
},
"messages": {
"welcome": "Welcome to our platform",
"error": "An error occurred"
}
},
"version": "1.0.0",
"settings": {
"theme": "dark",
"notifications": true
}
},
"name": "App UI Translations",
"callback_url": "https://your-app.com/webhooks/translation-complete",
"target_languages": ["es", "fr", "de"]
}
Responses
Success Response
- Code:
201 Created - Content Type:
application/json
{
"id": 123,
"name": "App UI Translations",
"status": "queued",
"created_at": "2024-01-15T10:30:00.000Z",
"updated_at": "2024-01-15T10:30:00.000Z"
}Response Schema
| Field | Type | Description |
|---|---|---|
id | number | The unique identifier of the content translation job. |
name | string | The job name (auto-generated if not provided). |
status | string | The current job status (queued, processing, completed). |
created_at | string | The ISO 8601 timestamp indicating when the job was created. |
updated_at | string | The ISO 8601 timestamp indicating when the job was last updated. |
Error Responses
Invalid JSON Data
- Code:
422 Unprocessable Entity
{
"errors": {
"data": ["Data must be a valid JSON object"]
}
}
Invalid Target Languages
- Code:
422 Unprocessable Entity
{
"errors": {
"target_languages": ["Language codes [zh, xx] are not configured for this project"]
}
}
Unauthorized
- Code:
401 Unauthorized
{
"error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
- Code:
403 Forbidden
{
"error": "Access denied. Insufficient permissions."
}
JSON Data Processing
When working with JSON-structured data, PTC processes the data as follows:
- Structure is preserved – The original hierarchy of keys and nesting remains unchanged
- Only strings are translated – Numbers, booleans, arrays, and null values are kept as they are
- Path-based translation – Each translatable string is identified by its JSON path
- Supports nesting – Works with deeply nested objects and arrays
- Handles mixed data types – Non-string values are preserved without modification
Example Data Transformation
Input:
{
"user": {
"name": "Welcome User",
"settings": {
"theme": "Choose Theme",
"count": 5,
"enabled": true
}
}
}
Processing outcome:
user.name: “Welcome User” → Gets translateduser.settings.theme: “Choose Theme” → Gets translateduser.settings.count:5 → Remains unchangeduser.settings.enabled:true → Remains unchanged
Translation Workflow
- Validation: JSON structure and target languages are checked
- Source file preparation: JSON is converted to an internal source format
- String reuse through translation memory: All translatable strings are extracted and stored in your project’s translation memory so previous translations can be reused
- Job queuing: A job is queued for each target language
- Processing: Automatic translation runs on the extracted strings
- Callback (optional): A webhook is sent when all translations are completed, if
callback_urlis provided
Webhook Callback
When a callback_url is provided, a POST request is sent when the job is completed.
Callback request body:
{
"id": 1,
"status": "completed",
"translations_url": "https://app.ptc.wpml.org/api/v1/content_translation/1"
}Supported Data Types
| JSON Type | Translation Behavior |
|---|---|
string | Translated to target languages |
number | Preserved as-is |
boolean | Preserved as-is |
null | Preserved as-is |
array | Processed recursively |
object | Processed recursively |
Example Requests
Basic JSON translation:
curl -X POST "https://app.ptc.wpml.org/api/v1/content_translation" \
-H "Content-Type: application/json" \
-d '{
"data": {
"welcome": "Welcome",
"buttons": {
"save": "Save",
"cancel": "Cancel"
}
},
"name": "UI Labels"
}'
With specific target languages:
curl -X POST "https://app.ptc.wpml.org/api/v1/content_translation" \
-H "Content-Type: application/json" \
-d '{
"data": {
"title": "Product Catalog",
"categories": {
"electronics": "Electronics",
"clothing": "Clothing"
}
},
"target_languages": ["es", "fr"],
"callback_url": "https://myapp.com/webhook"
}'
Code Examples
const translationData = {
data: {
app: {
title: "My Application",
navigation: {
home: "Home",
about: "About Us"
}
}
},
name: "App Translations",
target_languages: ["es", "fr", "de"],
callback_url: "https://your-app.com/webhooks/complete"
};
const response = await fetch('https://app.ptc.wpml.org/api/v1/content_translation', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(translationData)
});
const result = await response.json();
console.log('Translation job created:', result);
// Store the ID for later retrieval
const translationId = result.id;
import requests
translation_data = {
"data": {
"app": {
"title": "My Application",
"navigation": {
"home": "Home",
"about": "About Us"
}
}
},
"name": "App Translations",
"target_languages": ["es", "fr", "de"],
"callback_url": "https://your-app.com/webhooks/complete"
}
headers = {
'Content-Type': 'application/json'
}
response = requests.post('https://app.ptc.wpml.org/api/v1/content_translation',
headers=headers, json=translation_data)
result = response.json()
print(f"Translation job created with ID: {result['id']}")
print(f"Status: {result['status']}")<?php
$translationData = [
'data' => [
'app' => [
'title' => 'My Application',
'navigation' => [
'home' => 'Home',
'about' => 'About Us'
]
]
],
'name' => 'App Translations',
'target_languages' => ['es', 'fr', 'de'],
'callback_url' => 'https://your-app.com/webhooks/complete'
];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://app.ptc.wpml.org/api/v1/content_translation',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($translationData),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json'
],
]);
$response = curl_exec($curl);
curl_close($curl);
$result = json_decode($response, true);
echo "Translation job created with ID: " . $result['id'];
?>
const axios = require('axios');
const translationData = {
data: {
app: {
title: "My Application",
navigation: {
home: "Home",
about: "About Us"
}
}
},
name: "App Translations",
target_languages: ["es", "fr", "de"],
callback_url: "https://your-app.com/webhooks/complete"
};
const response = await axios.post('https://app.ptc.wpml.org/api/v1/content_translation', translationData, {
headers: {
'Content-Type': 'application/json'
}
});
console.log('Translation job created:', response.data);
// Monitor status
const checkStatus = async (id) => {
const statusResponse = await axios.get(`https://app.ptc.wpml.org/api/v1/content_translation/${id}/status`);
return statusResponse.data.status;
};
Get Content Translations
Retrieves the original content and all translated versions for a specific content translation job.
The response preserves your input structure: it returns a source object plus one object per target language (keyed by language code such as es, fr, de).
HTTP Request
GET https://app.ptc.wpml.org/api/v1/content_translation/{id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The unique identifier of the content translation job to retrieve. |
Responses
Success Response
- Code:
200 OK - Content Type:
application/json
{
"source": {
"app": {
"title": "My Application",
"navigation": {
"home": "Home",
"about": "About",
"contact": "Contact"
},
"buttons": {
"save": "Save",
"cancel": "Cancel"
}
}
},
"es": {
"app": {
"title": "Mi Aplicación",
"navigation": {
"home": "Inicio",
"about": "Acerca de",
"contact": "Contacto"
},
"buttons": {
"save": "Guardar",
"cancel": "Cancelar"
}
}
},
"fr": {
"app": {
"title": "Mon Application",
"navigation": {
"home": "Accueil",
"about": "À propos",
"contact": "Contact"
},
"buttons": {
"save": "Enregistrer",
"cancel": "Annuler"
}
}
}
}Response Schema
| Field | Type | Description |
|---|---|---|
source | object | The original source content in the same nested structure as submitted. |
{language_code} | object | The translated content for each target language, keyed by its ISO code (for example es, fr, de), with the same structure as source.For more information, see the Available Target Languages API. |
Error Responses
Content Translation Not Found
- Code:
404 Not Found
{
"error": "Content translation not found"
}
Unauthorized
- Code:
401 Unauthorized
{
"error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
- Code:
403 Forbidden
{
"error": "Access denied. Insufficient permissions."
}
Example Requests
Basic request:
curl -X GET "https://app.ptc.wpml.org/api/v1/content_translation/123" \
-H "Content-Type: application/json"Code Examples
const contentTranslationId = 123;
const response = await fetch(`https://app.ptc.wpml.org/api/v1/content_translation/${contentTranslationId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
// Access source content
console.log('Source title:', data.source.app.title);
// Access translated content
console.log('Spanish title:', data.es.app.title);
console.log('French title:', data.fr.app.title);
// Iterate through all languages
Object.keys(data).forEach(langCode => {
if (langCode !== 'source') {
console.log(`${langCode} translation:`, data[langCode]);
}
});
import requests
content_translation_id = 123
headers = {
'Content-Type': 'application/json'
}
response = requests.get(f'https://app.ptc.wpml.org/api/v1/content_translation/{content_translation_id}',
headers=headers)
data = response.json()
# Access source content
source_data = data['source']
print("Source content:", source_data)
# Access translations
for lang_code, translation in data.items():
if lang_code != 'source':
print(f"{lang_code.upper()} translation:", translation)<?php
$content_translation_id = 123;
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.ptc.wpml.org/api/v1/content_translation/{$content_translation_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json'
],
]);
$response = curl_exec($curl);
curl_close($curl);
$data = json_decode($response, true);
// Access source content
$sourceData = $data['source'];
echo "Source content: " . json_encode($sourceData, JSON_PRETTY_PRINT) . "\n";
// Access translations
foreach ($data as $langCode => $translation) {
if ($langCode !== 'source') {
echo strtoupper($langCode) . " translation: " . json_encode($translation, JSON_PRETTY_PRINT) . "\n";
}
}
?>
const axios = require('axios');
const contentTranslationId = 123;
const response = await axios.get(`https://app.ptc.wpml.org/api/v1/content_translation/${contentTranslationId}`, {
headers: {
'Content-Type': 'application/json'
}
});
const data = response.data;
// Function to traverse nested objects
function extractStrings(obj, path = '') {
const strings = [];
for (const [key, value] of Object.entries(obj)) {
const currentPath = path ? `${path}.${key}` : key;
if (typeof value === 'string') {
strings.push({ path: currentPath, value });
} else if (typeof value === 'object') {
strings.push(...extractStrings(value, currentPath));
}
}
return strings;
}
// Extract all translatable strings
const sourceStrings = extractStrings(data.source);
console.log('Source strings:', sourceStrings);
// Compare with translations
Object.keys(data).forEach(langCode => {
if (langCode !== 'source') {
const translatedStrings = extractStrings(data[langCode]);
console.log(`${langCode} strings:`, translatedStrings);
}
});
Get the Content Translation Status
Retrieves the current status of a specific content translation job.
The response reflects the overall progress and includes whether the translation is queued, in progress, completed, or has failed.
HTTP Request
GET https://app.ptc.wpml.org/api/v1/content_translation/{id}/statusPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The unique identifier of the content translation job to check. |
Responses
Success Response
- Code:
200 OK - Content Type:
application/json
{
"status": "completed",
"completeness": 100
}
Response Schema
| Field | Type | Description |
|---|---|---|
status | string | The current translation status. Possible status values include: queued, in_progress, completed, failed, status_unknown. |
completeness | number | The percentage of translated strings (0–100). Calculated as (completed_translatable_strings / total_translatable_strings) × 100. |
Status Values
| Status | Description |
|---|---|
queued | The translation has been queued and is waiting to be processed. |
in_progress | The translation is currently being processed. |
completed | The translation has been completed successfully. |
failed | The translation has failed due to an error. |
status_unknown | The translation status is unknown or cannot yet be determined. |
Error Responses
- Code:
404 Not Found
Possible causes:
- No content translation exists with the specified ID
- The translation job does not belong to the authenticated project
Example
curl -X GET "https://app.ptc.wpml.org/api/v1/content_translation/123/status" \
-H "Authorization: Bearer your-api-token"Response:
{
"status": "completed",
"completeness": 100
}GET https://app.ptc.wpml.org/api/v1/content_translation/{id}/status{
"status": "in_progress",
"completeness": 70
}curl -X GET "https://app.ptc.wpml.org/api/v1/content_translation/123/status" \
-H "Authorization: Bearer your-api-token"{
"status": "completed",
"completeness": 100
}