|
Knowledgebase
EnterprisePlatform
PlatformAPI
React (MCP)React (Lingo Compiler)
Alpha
CLIIntegrations
GuidesChangelog

Synchronous

  • How it works
  • Localize
  • Recognize
  • ProvisionEnterprise

AsynchronousEnterprise

  • How it works
  • Queue
  • Webhooks
  • WebSocket

Queue

Max PrilutskiyMax Prilutskiy·Updated 1 day ago·5 min read

Submit content for translation to multiple locales in a single request. The API creates one job per target locale, processes them independently through your localization engine, and delivers results via webhooks or WebSocket.

Create localization jobs#

text
POST /jobs/localization
ParameterTypeDescription
sourceLocalestringBCP-47 source locale (e.g., en)
targetLocalesstring[]Array of BCP-47 target locales (e.g., ["de", "fr", "ja"])
dataobjectKey-value content to translate. Supports nested objects and arrays.
hintsobject (optional)Contextual hints per key (array of breadcrumb strings)
callbackUrlstring (optional)HTTPS webhook URL for this job group. Overrides the organization default.
idempotencyKeystring (optional)Client-generated UUID to prevent duplicate job groups.
engineIdstring (optional)Localization engine ID. Uses the organization's default engine if omitted.

Request#

The data field accepts flat key-value pairs or nested structures with objects and arrays at any depth. The localization engine translates all string values, preserves non-string values (numbers, booleans, null) as-is, and maintains the exact structure of the input.

json
{
  "sourceLocale": "en",
  "targetLocales": ["de", "fr", "ja"],
  "data": {
    "lesson_title": "Introduction to Machine Learning",
    "lesson_summary": "This lesson covers the fundamentals of ML, including supervised and unsupervised learning."
  },
  "callbackUrl": "https://your-app.com/webhooks/translations",
  "idempotencyKey": "550e8400-e29b-41d4-a716-446655440000"
}

HTTPS required

The callbackUrl must use HTTPS. HTTP URLs are rejected with a 400 error.

Response (202 Accepted)#

json
{
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "status": "pending",
  "jobs": [
    { "id": "ljb_A1b2C3d4E5f6G7h8", "targetLocale": "de", "status": "queued" },
    { "id": "ljb_B2c3D4e5F6g7H8i9", "targetLocale": "fr", "status": "queued" },
    { "id": "ljb_C3d4E5f6G7h8I9j0", "targetLocale": "ja", "status": "queued" }
  ],
  "createdAt": "2026-03-16T10:30:00.000Z"
}

Examples#

javascript
const response = await fetch("https://api.lingo.dev/jobs/localization", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.LINGO_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    sourceLocale: "en",
    targetLocales: ["de", "fr", "ja"],
    data: {
      title: "Introduction to Machine Learning",
      steps: [
        { heading: "What is ML?", body: "Machine learning is a subset of AI." },
        { heading: "Supervised Learning", body: "Training with labeled data." },
      ],
    },
    callbackUrl: "https://your-app.com/webhooks/translations",
  }),
});

const { groupId, jobs } = await response.json();
// 202 back in milliseconds. 3 jobs queued.
// Results arrive via webhook as each language completes.
console.log(groupId); // "ljg_A1b2C3d4E5f6G7h8"
console.log(jobs.length); // 3

Get a job group#

Retrieve the status of a job group and all its child jobs. Use this to build progress indicators or check overall completion.

text
GET /jobs/localization/groups/:groupId

Response#

json
{
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "status": "processing",
  "sourceLocale": "en",
  "totalJobs": 3,
  "completedJobs": 1,
  "failedJobs": 0,
  "jobs": [
    { "id": "ljb_A1b2C3d4E5f6G7h8", "targetLocale": "de", "status": "completed", "completedAt": "2026-03-16T10:30:04.000Z" },
    { "id": "ljb_B2c3D4e5F6g7H8i9", "targetLocale": "fr", "status": "processing", "completedAt": null },
    { "id": "ljb_C3d4E5f6G7h8I9j0", "targetLocale": "ja", "status": "queued", "completedAt": null }
  ],
  "createdAt": "2026-03-16T10:30:00.000Z"
}
Group statusMeaning
pendingGroup created, no jobs started yet
processingAt least one job is in progress
completedAll jobs completed successfully
partialSome jobs completed, some failed
failedAll jobs failed

Polling interval

For most jobs, processing takes 2-8 seconds per language. If you're polling instead of using webhooks or WebSocket, a 2-second interval is a reasonable starting point.

Get a single job#

Retrieve full details for one job, including translated output when complete.

text
GET /jobs/localization/:jobId

Response#

The outputData field mirrors the structure of the input data with all string values translated. Nested objects, arrays, and non-string values are preserved as-is.

json
{
  "id": "ljb_A1b2C3d4E5f6G7h8",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "targetLocale": "de",
  "status": "completed",
  "outputData": {
    "id": "course_101",
    "title": "Einführung in maschinelles Lernen",
    "steps": [
      { "heading": "Was ist ML?", "body": "Maschinelles Lernen ist ein Teilbereich der künstlichen Intelligenz." },
      { "heading": "Überwachtes Lernen", "body": "Trainieren eines Modells mit gelabelten Daten." }
    ],
    "metadata": { "author": "Dr. Smith", "difficulty": "beginner" }
  },
  "errorMessage": null,
  "callbackStatus": "delivered",
  "createdAt": "2026-03-16T10:30:00.000Z",
  "startedAt": "2026-03-16T10:30:01.000Z",
  "completedAt": "2026-03-16T10:30:04.000Z"
}
FieldDescription
statusqueued, processing, completed, or failed
outputDataTranslated content matching the input structure. Present when status is completed.
errorMessageError description. Present when status is failed.
callbackStatusWebhook delivery state: pending, delivered, or failed.

List jobs#

text
GET /jobs/localization?engineId=eng_abc123&status=completed&limit=20&cursor=...

Returns a paginated list of jobs, ordered by creation time (newest first). Filter by engineId or status. Use the nextCursor value from the response to fetch subsequent pages.

ParameterTypeDescription
engineIdstring (optional)Filter by localization engine ID
statusstring (optional)Filter by job status: queued, processing, completed, or failed
limitnumber (optional)Max results per page (default 20, max 100)
cursorstring (optional)Opaque cursor from a previous response's nextCursor

Response#

json
{
  "items": [
    {
      "id": "ljb_C3d4E5f6G7h8I9j0",
      "groupId": "ljg_A1b2C3d4E5f6G7h8",
      "targetLocale": "ja",
      "status": "completed",
      "createdAt": "2026-03-16T10:30:00.000Z",
      "completedAt": "2026-03-16T10:30:06.000Z"
    }
  ],
  "nextCursor": "eyJ0IjoiMjAyNi0wMy0xNlQxMDozMDowMC4wMDBaIiwiaSI6ImxqYl9CMmMzRDRlNUY2ZzdIOGk5In0"
}

Best practices#

Use idempotency keys#

If your application might submit the same translation request twice (e.g., due to retries or duplicate events), pass an idempotencyKey. The platform returns the existing job group instead of creating a duplicate. Keys are scoped per localization engine.

A natural idempotency key combines content identity with version: {contentId}-v{contentVersion}. This ensures a new job group is created only when the content actually changes.

Handle partial failures#

Each language is an independent job. If German succeeds but Japanese fails, the German translation is delivered normally via webhook. The failed Japanese job appears with status: "failed" and an errorMessage. The job group status becomes partial.

To retry failed languages, submit a new request with only the failed locales and a fresh idempotency key.

Next Steps#

Webhooks
Receive translation results via webhook callbacks
WebSocket
Stream real-time progress updates to your UI
How it works
Overview of the async localization API

Was this page helpful?