|
Documentation
Book a DemoPlatform
PlatformMCPCLIAPI
Workflows
GuidesChangelog

Welcome

  • Overview
  • Authentication
  • Errors & status codes
  • Webhook signatures

Localization

  • Overview
  • Create jobs
  • Lock non-translatable keys
  • Track a job group
  • Get a single job
  • List jobs
  • Webhook delivery
  • Live progress (WebSocket)

Pipeline

  • Overview
  • Pre-localization AI edit
  • Human review
  • AI review (post-edit)
  • Rephrase for natural copy
  • Back-translation check
  • Configure the pipeline
  • Observe pipeline runs

Provisioning

  • Overview
  • Create a provisioning job
  • Source types
  • What the AI extracts
  • Webhook delivery
  • Live progress (WebSocket)

Synchronous

  • Localize
  • Recognize

Engine management

  • Engine Suggestions

Create localization jobs

Create a localization job group: one request that fans your content out to every target locale you name.

You have a payload of strings and a list of locales, and you want to translate them all without writing the fan-out yourself. POST /jobs/localization takes the whole payload and up to 100 target locales in a single request, then returns 202 Accepted right away with a group ID and one job per locale. One request, every locale – the platform creates the jobs and processes each one independently.

text
POST /jobs/localization

This page covers the create call: its parameters, the request shape, the 202 response, and how to make the call safe to retry. New to async localization? Start with the Async Localization API overview for the mental model. Once a group exists, tracking a job group tells you what each locale's status means.

Authentication

Pass your API key in the X-API-Key header. Keys are organization-scoped and reach every engine in the organization. See Authentication for details.

Parameters#

sourceLocale, targetLocales, and data are required. Everything else tunes behavior or makes the call safer to repeat.

ParameterTypeDescription
sourceLocalestringBCP-47 source locale (e.g. en).
targetLocalesstring[]BCP-47 target locales (e.g. ["de", "fr", "ja"]). 1–100 per request. One job is created per locale.
dataobjectKey-value content to translate. Nested objects and arrays are allowed at any depth.
contextstring (optional)Broad context for this translation payload, such as the product surface, audience, or purpose. Applies to every job created for the request.
hintsobject (optional)Per-key context as arrays of breadcrumb strings, to disambiguate short or reused strings.
callbackUrlstring (optional)HTTPS webhook URL for this group. Overrides the organization default. HTTP is rejected.
idempotencyKeystring (optional)Client-generated key. Send the same request twice with the same key and the existing group is returned instead of a new one. Scoped per engine.
engineIdstring (optional)Localization engine to run the jobs through. Falls back to the organization's default engine when omitted.
pipelineConfigobject (optional)Per-request pipeline overrides. Stages you omit inherit from the engine config.
lockedKeysstring[] (optional)Keys or glob patterns whose values are excluded from translation and merged back verbatim into outputData. Up to 100 patterns. See Lock non-translatable keys.

Request#

The data field accepts flat key-value pairs or nested structures with objects and arrays at any depth. The engine translates every string value, preserves non-string values (numbers, booleans, null) untouched, and returns the exact shape you sent. So you can hand it the same object your app already stores – no flattening, no reshaping.

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": "course_101-v3"
}

HTTPS required

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

That nested payload mixes translatable text with values that must survive untouched – id, course_101, difficulty. Strings are translated; the rest is preserved by type. When you need a string held back too (a slug, an asset URL, an enum code), name it in lockedKeys and it is merged back verbatim into every locale's output.

Response (202 Accepted)#

The call returns immediately. It does not wait for translation – it hands you the group ID and the per-locale job IDs, then the platform processes each job independently in the background.

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"
}
FieldDescription
groupIdljg_-prefixed identifier for the whole group. Store this – it is the handle for tracking and live progress.
statusGroup status at creation, normally pending.
jobsOne entry per target locale: id (ljb_-prefixed), targetLocale, and the job's status.
createdAtISO 8601 timestamp.

Three locales in, three jobs back, each queued and ready to run. What each status means as the jobs progress – and what happens when one locale fails while the others ship – lives on Track a job group.

Examples#

The same request from Node and Python. Both fire one POST and read the group ID and job count straight off the 202.

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 Accepted – the call returns without waiting for translation.
console.log(groupId);     // "ljg_A1b2C3d4E5f6G7h8"
console.log(jobs.length); // 3 – one queued job per target locale

Make the call safe to retry#

The natural place to fire this request is a save hook or an event handler – exactly the code that runs twice when a retry fires or a duplicate event arrives. Without protection, two calls mean two job groups, and the same content is queued for translation twice.

Pass an idempotencyKey and that stops being a risk. Send the same request twice with the same key and the platform returns the existing group instead of creating a new one – no second set of jobs. Keys are scoped per engine, so the same key against a different engine is a different group.

Pick a key that means something

A good key combines content identity with version: {contentId}-v{contentVersion}. The same content at the same version always resolves to the same group, so a retry is automatically a no-op. Bump the version when the content changes and you get a fresh group.

javascript
const key = `${content.id}-v${content.version}`;

async function submit() {
  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", "ko", "pt-BR"],
      data: { title: content.title, steps: content.steps },
      callbackUrl: "https://your-app.com/webhooks/translations",
      idempotencyKey: key,
    }),
  });
  return (await response.json()).groupId;
}

const first = await submit();
const again = await submit(); // same key – duplicate submission
console.log(first === again); // true – same group returned, no second set of jobs

This is the one POST that fans a payload out to every locale, and it is safe to fire from the same code path that retries. Store the groupId; that is what you carry into tracking and live progress.

Next steps#

Lock non-translatable keys
Hold IDs, slugs, asset URLs, and enum codes back from translation with key and glob patterns.
Configure the pipeline
Override pipeline stages per request, or set engine-level defaults that every job inherits.
Track a job group
Read group and per-locale status, and handle the case where one locale fails while the rest ship.

Was this page helpful?

Max PrilutskiyMax Prilutskiy·Updated 2 days ago·6 min read