Upload and Manage Source Files via the API

Use this API to upload new source files, replace outdated ones, track translation progress, and download completed translations.

Whether you’re managing a single file or automating a continuous localization workflow, this API gives you full control over the content you send for translation and how you receive the translations.

How the PTC API Identifies and Organizes Source Files

The PTC API uses a flexible system based on file tags and file paths. These parameters work together to ensure every file you upload, update, or request is clearly defined and easy to manage.

File Tags

File tags are a flexible way to group and organize source files in translation projects. You can use them like categories to match your workflow needs. For example, file tags can show:

  • Version control: v1.0, beta, production
  • Feature branches: user-auth, dashboard-redesign
  • Application context: mobile-app, admin-panel, marketing
  • Team ownership: frontend-team, content-team
  • Workflow state: approved, pending-review, priority-high

File tag names are optional in most API operations. However, every source file always has at least one tag. A default file tag is automatically created and assigned when a project is set up. This default behavior keeps projects organized even in simple setups, while still allowing you to build more advanced tagging structures when needed.

File Tag Name + File Path

Each source file is uniquely identified by the combination of its file tag name and file path.

  • If you do not provide a custom file tag when uploading or processing a file, the default tag will be assigned automatically.
  • A file’s tag name + path together define its identity. This combination ensures each file is unique within your project, even if different versions or contexts share the same file path.

Query Parameters

When retrieving a specific file, related endpoints can accept query parameters such as:

  • file_tag_name – The tag associated with the file
  • file_path – The path to the file

These parameters allow you to precisely locate and retrieve the correct files from your project.


List All Source Files in The Project

Lists all the source files in your project, with options to filter, sort, and paginate the results. This is useful when you want to browse your files, check their status, or find specific files based on tag, path, or upload method.

HTTP Request

GET https://app.ptc.wpml.org/api/v1/source_files

Parameters

ParameterTypeRequiredDefaultDescription
pageintegerNo1The page number for pagination. Must be greater than 0.
per_pageintegerNo50The number of items per page. Must be greater than 0.
order_bystringNocreated_atThe field to sort by. Allowed values: id, created_at, updated_at.
sortstringNodescThe direction of sorting. Allowed values: asc, desc.
file_pathstringNoFilters by exact file path.
upload_originstringNoFilters by how the file was uploaded. Allowed values include: git, manual, api.

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/json
{
  "source_files": [
    {
      "id": 123,
      "file_path": "locales/en.po",
      "translation_path": "locales/{{lang}}.po",
      "additional_translation_files": ["locales/{{lang}}.mo"],
      "status": "completed",
      "upload_origin": "git",
      "created_at": "2024-01-15T10:30:00.000Z",
      "updated_at": "2024-01-15T14:20:00.000Z",
      "file_tag": {
        "id": 456,
        "name": "frontend"
      },
      "download_url": "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=locale/en.po&file_tag_name=frontend"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 150,
    "total_pages": 3,
    "has_next_page": true,
    "has_previous_page": false
  }
}
Response Schema

Source File Object:

FieldTypeDescription
idintegerThe unique identifier for the source file.
file_pathstringThe path to the source file within the project.
translation_pathstringThe pattern for where translated files should be saved.
additional_translation_filesarray[string]The paths for any additional output files.
statusstringThe current processing status of the source file.
upload_originstringHow the file was uploaded (git, manual, api).
created_atstringAn ISO 8601 timestamp indicating when the source file was originally created.
updated_atstringAn ISO 8601 timestamp indicating when the source file was last updated.
file_tagobjectInformation about the file tag.
file_tag.idintegerThe file tag identifier.
file_tag.namestringThe file tag name.
download_urlstringThe URL to download translations for this source file.

Pagination Object:

FieldTypeDescription
pageintegerThe current page number.
per_pageintegerThe number of items per page.
totalintegerThe total number of source files.
total_pagesintegerThe total number of pages.
has_next_pagebooleanWhether there is a next page available.
has_previous_pagebooleanWhether there is a previous page available.

Error Responses

Unauthorized
  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}
Invalid Parameters
  • Code: 422 Unprocessable Entity
{
  "error": "Invalid parameters provided."
}

Example Requests

Basic request:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files" \
  -H "Content-Type: application/json"

Filtered request:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files?file_tag_name=frontend&page=1&per_page=25&order_by=updated_at&sort=desc" \
  -H "Content-Type: application/json"

Code Examples

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files?file_tag_name=frontend&page=1&per_page=25', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);
import requests

headers = {
    'Content-Type': 'application/json'
}

params = {
    'file_tag_name': 'frontend',
    'page': 1,
    'per_page': 25
}

response = requests.get('https://app.ptc.wpml.org/api/v1/source_files', 
                       headers=headers, params=params)
data = response.json()
print(data)
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://app.ptc.wpml.org/api/v1/source_files?file_tag_name=frontend&page=1&per_page=25',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json'
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);
?>
const axios = require('axios');

const response = await axios.get('https://app.ptc.wpml.org/api/v1/source_files', {
  headers: {
    'Content-Type': 'application/json'
  },
  params: {
    file_tag_name: 'frontend',
    page: 1,
    per_page: 25
  }
});

console.log(response.data);

Get Translation Strings

Retrieves all translatable strings from a specific source file, along with their existing translations in all target languages.

This endpoint is useful for fetching content that needs to be translated or has already been translated. The source file is identified by file_path and file_tag_name.

HTTP Request

GET https://app.ptc.wpml.org/api/v1/source_files/translation_strings

Parameters

ParameterTypeRequiredDefaultDescription
file_pathstringYesThe path to the source file within the project.
file_tag_namestringNoThe file tag name. If not provided, the project’s default tag is used.
pageintegerNo1The page number for pagination (used as a cursor). Must be greater than 0.
qstringNoThe search query to filter translation strings by their source text.

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/json
{
  "total_strings_count": 1250,
  "translation_strings": [
    {
      "source": "Welcome to our application",
      "translations": {
        "es": "Bienvenido a nuestra aplicación",
        "fr": "Bienvenue dans notre application",
        "de": "Willkommen in unserer Anwendung"
      }
    },
    {
      "source": "Login",
      "translations": {
        "es": "Iniciar sesión",
        "fr": "Connexion",
        "de": "Anmelden"
      }
    }
  ],
  "cursor": 1
}
Response Schema
FieldTypeDescription
total_strings_countintegerThe total number of translatable strings in the source file.
translation_stringsarray[object]The array of translation string objects (paginated, max 500 per page).
translation_strings[].sourcestringThe original source text to be translated.
translation_strings[].translationsobjectA hash of translations where the keys are language ISO codes and the values are the translated text.
cursorintegerThe current page cursor used for pagination.

Error Responses

Source File Not Found
  • Code: 404 Not Found
{
  "error": "Source file not found"
}
Unauthorized
  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}
Invalid Parameters
  • Code: 422 Unprocessable Entity
{
  "error": "Invalid parameters provided."
}

Example Requests

Basic request:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/translation_strings?file_path=locales/en.po" \
  -H "Content-Type: application/json"

A request with file tag:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/translation_strings?file_path=locales/en.po&file_tag_name=frontend" \
  -H "Content-Type: application/json"

A request with pagination and search:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/translation_strings?file_path=locales/en.po&file_tag_name=frontend&page=2&q=welcome" \
  -H "Content-Type: application/json"

Code Examples

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files/translation_strings?file_path=locales/en.po&file_tag_name=frontend&page=1&q=login', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(data);

import requests

headers = {
    'Content-Type': 'application/json'
}

params = {
    'file_path': 'locales/en.po',
    'file_tag_name': 'frontend',
    'page': 1,
    'q': 'login'
}

response = requests.get('https://app.ptc.wpml.org/api/v1/source_files/translation_strings', 
                       headers=headers, params=params)
data = response.json()
print(data)
<?php
$params = http_build_query([
    'file_path' => 'locales/en.po',
    'file_tag_name' => 'frontend',
    'page' => 1,
    'q' => 'login'
]);

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://app.ptc.wpml.org/api/v1/source_files/translation_strings?{$params}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json'
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);
?>

const axios = require('axios');

const response = await axios.get('https://app.ptc.wpml.org/api/v1/source_files/translation_strings', {
  headers: {
    'Content-Type': 'application/json'
  },
  params: {
    file_path: 'locales/en.po',
    file_tag_name: 'frontend',
    page: 1,
    q: 'login'
  }
});

console.log(response.data);


Create the Source File

Registers a new source file in your project so it’s ready for translation.

This endpoint creates the file entry and sets up its translation configuration, but does not attach the actual file content.

After creating the file, you’ll need to use the Process the Source File endpoint to upload the content and start the translation process.

HTTP Request

POST https://app.ptc.wpml.org/api/v1/source_files

Parameters

ParameterTypeRequiredDescription
file_pathstringYesThe path where the source file should be stored in the project. Must have a supported extension.
output_file_pathstringYesThe output path pattern for translated files. Use {{lang}} as a placeholder for the language code.
translationsarray[object]NoThe pre-existing translation files to upload alongside the source file. These files will be stored as provided, and their strings will not be re-translated by PTC. 
Note that providing existing translations is not recommended, as PTC produces better results when it can use your project’s full context and translate from scratch.
translations[].target_language_isostringYesThe ISO code of the target language for this translation. You can find the full list of supported languages and their ISO codes in the List All Target Languages endpoint.
translations[].filefileYesThe translation file to upload.
additional_translation_filesarray[object]NoAdditional output file configurations for specific formats. 
To see which formats support additional output files, refer to the List Supported File Formats endpoint. For unsupported formats, this field will be ignored.
additional_translation_files[].typestringYesSee supported file formats for more details.
additional_translation_files[].pathstringYesThe path pattern for the file.

Responses

Success Response

  • Code: 201 Created
  • Content Type: application/json
{
  "source_file": {
    "id": 123,
    "file_path": "src/locales/en.json",
    "created_at": "2024-01-15T10:30:00.000Z",
    "file_tag": {
      "id": 456,
      "name": "frontend"
    }
  }
}
Response Schema
FieldTypeDescription
source_file.idintegerThe unique identifier for the created source file.
source_file.file_pathstringThe path of the source file within the project.
source_file.created_atstringAn ISO 8601 timestamp indicating when the source file was originally created.
source_file.file_tag.idintegerThe file tag identifier.
source_file.file_tag.namestringThe file tag name.

Error Responses

Validation Failed
  • Code: 422 Unprocessable Entity
{
  "success": false,
  "error": "Source file creation failed"
}
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 source file creation:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files" \
  -H "Content-Type: multipart/form-data" \
  -F "file_path=src/locales/en.json" \
  -F "output_file_path=src/locales/{lang}.json" \
  -F "file_tag_name=frontend"

Request with callback URL:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files" \
  -H "Content-Type: multipart/form-data" \
  -F "file_path=src/locales/messages.po" \
  -F "output_file_path=locales/{lang}/messages.po" \
  -F "callback_url=https://your-app.com/webhooks/translation-complete"

Request with pre-existing translations:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files" \
  -H "Content-Type: multipart/form-data" \
  -F "file_path=src/messages.json" \
  -F "output_file_path=locales/{lang}/messages.json" \
  -F "translations[0][target_language_iso]=es" \
  -F "translations[0][file]=@spanish_translations.json" \
  -F "translations[1][target_language_iso]=fr" \
  -F "translations[1][file]=@french_translations.json"

Request with additional output files:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files" \
  -H "Content-Type: multipart/form-data" \
  -F "file_path=src/messages.po" \
  -F "output_file_path=locales/{lang}/messages.po" \
  -F "additional_translation_files[mo]=locales/{lang}/messages.mo" \
  -F "additional_translation_files[json]=locales/{lang}/messages.json"

Code Examples

const formData = new FormData();
formData.append('file_path', 'src/locales/en.json');
formData.append('output_file_path', 'src/locales/{lang}.json');
formData.append('file_tag_name', 'frontend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files', {
  method: 'POST',
  body: formData
});

const data = await response.json();
console.log(data);


import requests

data = {
    'file_path': 'src/locales/en.json',
    'output_file_path': 'src/locales/{lang}.json',
    'file_tag_name': 'frontend',
    'callback_url': 'https://your-app.com/webhooks/complete'
}

response = requests.post('https://app.ptc.wpml.org/api/v1/source_files', data=data)
result = response.json()
print(result)

<?php
$data = [
    'file_path' => 'src/locales/en.json',
    'output_file_path' => 'src/locales/{lang}.json',
    'file_tag_name' => 'frontend',
    'callback_url' => 'https://your-app.com/webhooks/complete'
];

$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => 'https://app.ptc.wpml.org/api/v1/source_files',
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $data,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = curl_exec($curl);
curl_close($curl);

$result = json_decode($response, true);
print_r($result);
?>

const axios = require('axios');
const FormData = require('form-data');

const formData = new FormData();
formData.append('file_path', 'src/locales/en.json');
formData.append('output_file_path', 'src/locales/{lang}.json');
formData.append('file_tag_name', 'frontend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await axios.post('https://app.ptc.wpml.org/api/v1/source_files', formData, {
  headers: formData.getHeaders()
});

console.log(response.data);


{
  "source_file_id": 123,
  "status": "completed",
  "file_tag_name": "frontend",
  "download_url": "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=src/locales/en.json&file_tag_name=frontend",
  "file_path": "src/locales/en.json"
}

Process the Source File

Uploads content to an existing source file and starts the translation process. 

This endpoint replaces the file’s current content, updates the stored translatable strings, and starts automatic translation.

To use this endpoint, the source file must already exist in the project. If you haven’t created it yet, see Create the Source File.

HTTP Request

PUT https://app.ptc.wpml.org/api/v1/source_files/process

Parameters

ParameterTypeRequiredDescription
filefileYesThe source file to upload. The file content is validated to ensure it matches its declared extension. For example, if the file extension is .json, the uploaded content must be valid JSON.
file_pathstringYesThe path to the existing source file in the project that should be updated.
file_tag_namestringNoThe name of the file tag associated with the source file. If not provided, the project’s default file tag is used.
callback_urlstringNoThe URL that receives webhook notifications when file processing is complete.

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/json
{
  "source_file": {
    "id": 123,
    "file_path": "src/locales/en.json",
    "created_at": "2024-01-15T10:30:00.000Z",
    "file_tag": {
      "id": 456,
      "name": "frontend"
    }
  }
}
Response Schema
FieldTypeDescription
source_file.idintegerThe unique identifier for the processed source file.
source_file.file_pathstringThe path of the source file within the project.
source_file.created_atstringAn ISO 8601 timestamp indicating when the source file was originally created.
source_file.file_tag.idintegerThe file tag identifier.
source_file.file_tag.namestringThe file tag name.

Error Responses

Source File Not Found
  • Code: 422 Unprocessable Entity
{
  "errors": {
    "file": ["File format is invalid or not supported"]
  }
}
Unauthorized
  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}

Workflow

  1. Prerequisite: The source file must already be created via Create the Source File.
  2. File Upload: New content is uploaded and replaces the existing file content.
  3. Processing: The new translatable strings are extracted and automatically translated.
  4. Callback: An optional webhook notification is sent when processing finishes.

Webhook Callback

When a callback_url is provided, PTC will send a POST request to that URL when processing completes.

Callback request body:

{
  "source_file_id": 123,
  "status": "completed",
  "file_tag_name": "frontend",
  "download_url": "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=src/locales/en.json&file_tag_name=frontend",
  "file_path": "src/locales/en.json"
}

Example Requests

Basic file processing:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files/process" \
  -H "Content-Type: multipart/form-data" \
  -F "file=@updated_translations.json" \
  -F "file_path=src/locales/en.json" \
  -F "file_tag_name=frontend"

Request with callback URL:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files/process" \
  -H "Content-Type: multipart/form-data" \
  -F "file=@messages.po" \
  -F "file_path=locales/messages.po" \
  -F "callback_url=https://your-app.com/webhooks/translation-complete"

Code Examples

const formData = new FormData();
const fileInput = document.getElementById('file-input');
formData.append('file', fileInput.files[0]);
formData.append('file_path', 'src/locales/en.json');
formData.append('file_tag_name', 'frontend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files/process', {
  method: 'POST',
  body: formData
});

const data = await response.json();
console.log(data);

import requests

files = {'file': open('updated_translations.json', 'rb')}
data = {
    'file_path': 'src/locales/en.json',
    'file_tag_name': 'frontend',
    'callback_url': 'https://your-app.com/webhooks/complete'
}

response = requests.post('https://app.ptc.wpml.org/api/v1/source_files/process', 
                        files=files, data=data)
result = response.json()
print(result)
<?php
$file_path = 'updated_translations.json';
$post_data = [
    'file' => new CURLFile($file_path),
    'file_path' => 'src/locales/en.json',
    'file_tag_name' => 'frontend',
    'callback_url' => 'https://your-app.com/webhooks/complete'
];

$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => 'https://app.ptc.wpml.org/api/v1/source_files/process',
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $post_data,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = curl_exec($curl);
curl_close($curl);

$result = json_decode($response, true);
print_r($result);
?>


const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const formData = new FormData();
formData.append('file', fs.createReadStream('updated_translations.json'));
formData.append('file_path', 'src/locales/en.json');
formData.append('file_tag_name', 'frontend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await axios.post('https://app.ptc.wpml.org/api/v1/source_files/process', formData, {
  headers: formData.getHeaders()
});

console.log(response.data);

Supported File Formats

The endpoint supports various translatable file formats including JSON, PO/POT, XLIFF, and Properties files, among others.
File format validation occurs during upload to ensure compatibility.

 Use the List Supported File Formats endpoint to get the full list of supported formats.


Get the Translation Status

Retrieves the current translation progress for a specific source file, including how much is completed and its overall processing status.

This is useful for:

  • Progress monitoring – Tracking translation progress for long-running jobs
  • UI updates – Displaying completion percentages in your application
  • Workflow integration – Triggering actions when translation reaches a defined threshold

HTTP Request

GET https://app.ptc.wpml.org/api/v1/source_files/translation_status

Parameters

ParameterTypeRequiredDescription
file_pathstringYesThe path to the source file within the project.
file_tag_namestringNoThe file tag name. If not provided, the project’s default file tag is used.

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/json
{
  "translation_status": {
    "status": "completed",
    "completeness": 100
  }
}
Response Schema
FieldTypeDescription
translation_status.statusstringThe current processing status of the source file. See status values below.
translation_status.completenessnumberThe percentage of translated strings (0–100). Calculated as (completed_translatable_strings / total_translatable_strings) × 100.

Status Values

The status field can contain the following values:

StatusDescription
pendingThe source file is waiting to be processed.
processingThe translation is currently in progress.
completedAll translations have been completed.
failedThe translation process ran into errors.

Error Responses

Source File Not Found
  • Code: 404 Not Found
{
  "error": "Source file not found"
}
Unauthorized
  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}
Invalid Parameters
  • Code: 422 Unprocessable Entity
{
  "error": "Invalid parameters provided."
}

Example Requests

Basic request:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/translation_status?file_path=locales/en.po" \
  -H "Content-Type: application/json"

Request with file tag:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/translation_status?file_path=locales/en.po&file_tag_name=frontend" \
  -H "Content-Type: application/json"

Code Examples

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files/translation_status?file_path=locales/en.po&file_tag_name=frontend', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
console.log(`Translation ${data.translation_status.completeness}% complete`);

import requests

headers = {
    'Content-Type': 'application/json'
}

params = {
    'file_path': 'locales/en.po',
    'file_tag_name': 'frontend'
}

response = requests.get('https://app.ptc.wpml.org/api/v1/source_files/translation_status', 
                       headers=headers, params=params)
data = response.json()
print(f"Translation {data['translation_status']['completeness']}% complete")

<?php
$params = http_build_query([
    'file_path' => 'locales/en.po',
    'file_tag_name' => 'frontend'
]);

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://app.ptc.wpml.org/api/v1/source_files/translation_status?{$params}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json'
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
echo "Translation " . $data['translation_status']['completeness'] . "% complete";
?>
const axios = require('axios');

const response = await axios.get('https://app.ptc.wpml.org/api/v1/source_files/translation_status', {
  headers: {
    'Content-Type': 'application/json'
  },
  params: {
    file_path: 'locales/en.po',
    file_tag_name: 'frontend'
  }
});

console.log(`Translation ${response.data.translation_status.completeness}% complete`);


Download All Translations

Downloads all translated files for a specific source file as a ZIP archive.

This endpoint creates and returns a compressed archive containing all translation files in the target languages for the specified source file.

If no translations are available for the file, the request will return a 404 Not Found error.

HTTP Request

GET https://app.ptc.wpml.org/api/v1/source_files/download_translations

Parameters

ParameterTypeRequiredDescription
file_pathstringYesThe path to the source file within the project.
file_tag_namestringNoThe file tag name. If not provided, the project’s default file tag is used. A source file is uniquely identified by the combination of file_path and file_tag_name.

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/zip
  • Response Body: Binary ZIP file containing translation files
  • Headers:
    • Content-Type: application/zip
    • Content-Disposition: attachment; filename="translations-{source_file_id}.zip"
ZIP Archive Contents

The downloaded ZIP file contains:

  • Translation files – One per target language for the specified source file
  • Additional translation files – Additional generated files (if configured), placed at the root level following your configured paths
  • File structure – Matches the configuration set during source file creation

Example ZIP structure:

translations-123.zip
├── locales/es.json
├── locales/fr.json
├── locales/de.json
├── locales/es.po
├── locales/fr.po
├── locales/de.po
├── locales/es.mo
├── locales/fr.mo
├── locales/de.mo

Error Responses

Source File Not Found
  • Code: 404 Not Found
{
  "error": "Source file not found"
}
No Translations Available
  • Code: 404 Not Found
{
  "error": "No translations are available for this source file"
}
Unauthorized
  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}
Forbidden
  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}
Invalid Parameters
  • Code: 422 Unprocessable Entity
{
  "error": "Invalid parameters provided."
}

Example Requests

Basic request:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=locales/en.po" \
  -H "Content-Type: application/json" \
  -o translations.zip

Request with file tag:

curl -X GET "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=locales/en.po&file_tag_name=frontend" \
  -H "Content-Type: application/json" \
  -o frontend-translations.zip

Code Examples

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=locales/en.po&file_tag_name=frontend', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
});

if (response.ok) {
  const blob = await response.blob();
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'translations.zip';
  document.body.appendChild(a);
  a.click();
  window.URL.revokeObjectURL(url);
}

import requests

headers = {
    'Content-Type': 'application/json'
}

params = {
    'file_path': 'locales/en.po',
    'file_tag_name': 'frontend'
}

response = requests.get('https://app.ptc.wpml.org/api/v1/source_files/download_translations', 
                       headers=headers, params=params)

if response.status_code == 200:
    with open('translations.zip', 'wb') as f:
        f.write(response.content)
    print("Translations downloaded successfully")
<?php
$params = http_build_query([
    'file_path' => 'locales/en.po',
    'file_tag_name' => 'frontend'
]);

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://app.ptc.wpml.org/api/v1/source_files/download_translations?{$params}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json'
    ],
]);

$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);

if ($httpCode === 200) {
    file_put_contents('translations.zip', $response);
    echo "Translations downloaded successfully";
}
?>
const axios = require('axios');
const fs = require('fs');

const response = await axios.get('https://app.ptc.wpml.org/api/v1/source_files/download_translations', {
  headers: {
    'Content-Type': 'application/json'
  },
  params: {
    file_path: 'locales/en.po',
    file_tag_name: 'frontend'
  },
  responseType: 'stream'
});

response.data.pipe(fs.createWriteStream('translations.zip'));
console.log('Translations downloaded successfully');

Upload Source Files in Bulk

Uploads a ZIP archive containing multiple translatable files. Each file in the archive is extracted, validated, and processed. Supported formats are identified automatically.

This is the batch version of Process Source File, designed to speed up large-scale updates.

Additional Information

  • If a file matches an existing source file, it is updated with the new content, and translations are triggered again.
  • If a file is supported but does not match any existing source file, it is added to the not_found_files list and ignored.
  • Files with unsupported formats are listed under unsupported_files and ignored.
  • Files with invalid content are also listed under unsupported_files and ignored.
  • Large archives may take longer to process. Files are processed one by one to manage resources, so it is best to split very large uploads (more than 100 files) into smaller batches. All files in the archive are set to translate automatically.
  • The uploaded ZIP must be valid and readable. All files inside must be in a supported format. File names should not include special characters that could cause path issues.
  • If a callback_url is provided, a POST request is sent for each processed source file with its results.

HTTP Request

POST https://app.ptc.wpml.org/api/v1/source_files/bulk

Parameters

ParameterTypeRequiredDescription
zip_filefileYesA ZIP archive containing the source files to upload. It must be a valid ZIP file.
file_tag_namestringNoThe file tag name to associate with all source files in the archive. If not specified, the project’s default file tag is used. Each source file is uniquely identified by the combination of file_path and file_tag_name.
callback_urlstringNoThe URL that receives webhook notifications when each file is processed.

Expected ZIP File Structure

The ZIP file can contain source files in any directory structure. The directory structure is preserved, and files are processed recursively.

Example ZIP Structure:

source-files.zip
├── locales/
   ├── messages-en.po
   ├── validation-en.po
   └── admin-en.po
├── frontend/
   ├── components-en.json
   └── pages-en.json
   └── not-found-en.json
├── app-strings-en.properties
└── readme.txt (will be ignored)

Supported File Types:

  • JSON: .json files
  • Gettext: .po, .pot files
  • Properties: .properties files
  • YAML: .yml, .yaml files
  • XML: .xml files
  • Strings: .strings files
  • XLIFF: .xliff, .xlf files
  • CSV: .csv files
  • PHP: .php files

Responses

Success Response

  • Code: 200 OK
  • Content Type: application/json
{
  "success": true,
  "processed_files": [
    {
      "id": 123,
      "file_path": "locales/messages-en.po", 
      "created_at": "2024-01-15T10:30:00.000Z",
      "file_tag": {
        "id": 456,
        "name": "backend"
      }
    },
    {
      "id": 124,
      "file_path": "locales/validation-en.po",
      "created_at": "2024-01-15T10:30:05.000Z", 
      "file_tag": {
        "id": 456,
        "name": "backend"
      }
    }
  ],
  "unsupported_files": [
    "readme.txt",
    "config.ini"
  ],
  "not_found_files": ["frontend/not-found-en.json"]
}
Response Schema
FieldTypeDescription
successbooleanWhether the bulk upload operation was successful.
processed_filesarray[object]An array of source files that were successfully processed.
processed_files[].idintegerThe unique identifier for the created source file.
processed_files[].file_pathstringThe path of the source file, preserving the original ZIP structure.
processed_files[].created_atstringAn ISO 8601 timestamp indicating when the source file was created.
processed_files[].file_tagobjectThe file tag information.
processed_files[].file_tag.idintegerThe file tag identifier.
processed_files[].file_tag.namestringThe file tag name.
unsupported_filesarray[string]An array of file names that are not in a supported format.
not_found_filesarray[string]An array of supported files that did not match any existing source file and were ignored.

Error Responses

Invalid ZIP File

  • Code: 422 Unprocessable Entity
{
  "success": false,
  "error": "File format is invalid",
  "processed_files": [],
  "unsupported_files": []
}

Processing Failed

  • Code: 422 Unprocessable Entity
{
  "success": false,
  "error": "Failed to process ZIP archive",
  "processed_files": [],
  "unsupported_files": []
}

Unauthorized

  • Code: 401 Unauthorized
{
  "error": "Unauthorized access. Please provide a valid API token."
}

Forbidden

  • Code: 403 Forbidden
{
  "error": "Access denied. Insufficient permissions."
}

Webhook Callback

When a callback_url is provided, a POST request is sent for each processed file.

Callback request body (per file):

{
  "source_file_id": 123,
  "status": "completed",
  "file_tag_name": "backend",
  "download_url": "https://app.ptc.wpml.org/api/v1/source_files/download_translations?file_path=locales/messages-en.po&file_tag_name=backend",
  "file_path": "locale/en.po"
}

Example Requests

Basic bulk upload:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files/bulk" \
  -H "Content-Type: multipart/form-data" \
  -F "zip_file=@source-files.zip" \
  -F "file_tag_name=backend"

Request with callback URL:

curl -X POST "https://app.ptc.wpml.org/api/v1/source_files/bulk" \
  -H "Content-Type: multipart/form-data" \
  -F "zip_file=@translations.zip" \
  -F "file_tag_name=localization" \
  -F "callback_url=https://your-app.com/webhooks/bulk-complete"

Code Examples

const formData = new FormData();
const fileInput = document.getElementById('zip-file-input');
formData.append('zip_file', fileInput.files[0]);
formData.append('file_tag_name', 'backend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await fetch('https://app.ptc.wpml.org/api/v1/source_files/bulk', {
  method: 'POST',
  body: formData
});

const data = await response.json();
console.log(`Processed ${data.processed_files.length} files`);
console.log(`Unsupported files: ${data.unsupported_files.join(', ')}`);

import requests

files = {'zip_file': open('source-files.zip', 'rb')}
data = {
    'file_tag_name': 'backend',
    'callback_url': 'https://your-app.com/webhooks/complete'
}

response = requests.post('https://app.ptc.wpml.org/api/v1/source_files/bulk', 
                        files=files, data=data)
result = response.json()

print(f"Processed {len(result['processed_files'])} files")
print(f"Unsupported files: {', '.join(result['unsupported_files'])}")

<?php
$zip_file_path = 'source-files.zip';
$post_data = [
    'zip_file' => new CURLFile($zip_file_path),
    'file_tag_name' => 'backend',
    'callback_url' => 'https://your-app.com/webhooks/complete'
];

$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => 'https://app.ptc.wpml.org/api/v1/source_files/bulk',
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $post_data,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = curl_exec($curl);
curl_close($curl);

$result = json_decode($response, true);
echo "Processed " . count($result['processed_files']) . " files";
?>
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const formData = new FormData();
formData.append('zip_file', fs.createReadStream('source-files.zip'));
formData.append('file_tag_name', 'backend');
formData.append('callback_url', 'https://your-app.com/webhooks/complete');

const response = await axios.post('https://app.ptc.wpml.org/api/v1/source_files/bulk', formData, {
  headers: formData.getHeaders()
});

console.log(`Processed ${response.data.processed_files.length} files`);

Scroll to Top