Leia a saída traduzida de um idioma e o registro por etapa de como ela foi produzida.
Você recorre a isso quando já tem um jobId — retornado no 202 da criação, enviado em um webhook ou listado em um grupo de jobs. O endpoint de grupo informa quantos idiomas já foram concluídos. Este endpoint mostra o que um único idioma produziu e o que aconteceu ao longo do processo.
GET /jobs/localization/:jobIdEstá começando em localização assíncrona? Comece pela Visão geral.
Essa distinção é exatamente o motivo desta página existir. A resposta de um grupo é um placar — contagens e status por job, abordados na página de grupo de jobs. Já um job individual é o registro completo de um idioma: o outputData traduzido, o status terminal, qualquer warnings e o histórico em steps[] de cada etapa executada pelo pipeline. Quando chegar a hora de gravar o texto em alemão no seu banco de dados, é esta chamada que entrega esse texto em alemão.
Autenticação#
Passe sua chave de API no cabeçalho X-API-Key. As chaves têm escopo de organização e dão acesso a todos os engine da organização. Consulte Authentication para mais detalhes.
Resposta#
O campo outputData espelha a estrutura do data de entrada, com cada valor string traduzido e cada valor não string (números, booleanos, null) preservado no lugar. Mesmas chaves, mesmo aninhamento, mesma ordem nos arrays — só as strings mudam.
{
"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,
"warnings": [],
"callbackStatus": "delivered",
"createdAt": "2026-03-16T10:30:00.000Z",
"startedAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:04.000Z",
"steps": [
{
"stepId": "localize",
"type": "action",
"status": "completed",
"errorMessage": null,
"externalRefType": null,
"externalRefId": null,
"externalRefUrl": null,
"createdAt": "2026-03-16T10:30:01.000Z",
"startedAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:04.000Z"
}
]
}O bloco metadata acima permaneceu intacto — Dr. Smith e beginner são folhas não string que o engine deixou como estavam. O outputData que você recebe de volta mantém o formato do que foi enviado, então o mesmo código que montou o payload pode consumir a tradução.
| Campo | Descrição |
|---|---|
id | O ID deste job (ljb_…). É o valor que você passou no caminho. |
groupId | O grupo de jobs pai (ljg_…) ao qual este job pertence. Passe-o para o endpoint de grupo de jobs para ver todos os idiomas relacionados de uma só vez. |
targetLocale | O idioma BCP-47 para o qual este job traduziu — existe um job para cada idioma de destino. É neste campo que você faz a ramificação para encaminhar outputData para a coluna ou arquivo certo. |
status | queued, processing, completed, completed_with_warnings ou failed. |
outputData | Conteúdo traduzido que corresponde à estrutura de entrada. Está presente quando status é completed ou completed_with_warnings. |
errorMessage | Descrição do erro. Está presente quando status é failed; caso contrário, null. |
warnings | Falhas não críticas em etapas do pipeline. Cada entrada é { step, message }. Fica vazio, a menos que status seja completed_with_warnings. |
callbackStatus | Estado de entrega do webhook: pending, delivered ou failed. null se nenhuma URL de callback estiver configurada. |
createdAt | Quando o job foi aceito (o timestamp no 202 que o criou). |
startedAt | Quando o engine começou a traduzir este idioma. É definido assim que o job sai de queued. |
completedAt | Quando o job chegou a um estado terminal. É definido assim que status passa a ser completed, completed_with_warnings ou failed. |
steps | Registros de execução por etapa. Sempre inclui a etapa localize, além de uma entrada para cada etapa opcional do pipeline habilitada. O formato completo do registro está em Observe pipeline runs. |
outputData é null até o job terminar
Enquanto status for queued ou processing, outputData estará vazio e errorMessage será null — ainda não há nada para ler. Leia outputData somente depois que status chegar a completed ou completed_with_warnings; em caso de failed, leia errorMessage. Faça a ramificação com base em status primeiro e só então acesse o payload.
Valores de status do job#
Um job vai de queued para processing e então para exatamente um estado terminal. Faça a ramificação com base em status antes de ler qualquer outra coisa — é ele que informa quais campos estão preenchidos.
| Status | Significado | O que ler |
|---|---|---|
queued | Aceito, mas ainda não iniciado. | Nada ainda — faça polling ou aguarde o webhook. |
processing | O engine está traduzindo este idioma. | Nada ainda. |
completed | A tradução terminou e todas as etapas habilitadas foram concluídas com sucesso. | outputData. |
completed_with_warnings | A tradução terminou e outputData está completo, mas uma etapa não crítica do pipeline falhou. | outputData, depois warnings. |
failed | O job não produziu tradução. | errorMessage. |
completed_with_warnings ainda entrega uma tradução
completed_with_warnings não é uma falha leve. Você recebe outputData completo — a etapa principal de tradução foi concluída com sucesso. O que muda é que uma etapa não crítica (por exemplo, pre-edit ou back-translation) não foi concluída, e cada falha é registrada em warnings como { step, message }. Trate a saída como utilizável; trate warnings como um sinal de qualidade que vale a pena mostrar a quem faz a revisão das traduções. Só failed significa que não há tradução para ler.
Trate valores de status desconhecidos
Os cinco valores de status acima são o contrato atual. As etapas do pipeline evoluem, então trate status como um conjunto aberto: faça a ramificação com base nos valores que você conhece e encaminhe qualquer coisa inesperada para um padrão que leia outputData se ele estiver presente e registre logs caso contrário. Um switch sem fallback é a linha que vai quebrar no dia em que um novo estado for lançado.
O array steps#
steps[] é o histórico por etapa por trás de um único job — um registro para cada etapa que o engine executou, em ordem. Todo job inclui pelo menos a etapa localize, porque a tradução principal sempre roda. Cada etapa opcional do pipeline que você habilita adiciona mais um registro. Então, um job sem etapas extras mostra uma única etapa localize; um job com pre-edit e back-translation habilitados mostra três.
É isso que torna um job auditável, e não uma caixa-preta. Você não precisa confiar que uma etapa foi executada — basta ler o registro dela: qual etapa (stepId), se ela completed, failed ou foi skipped, quanto custou (costUsd) e quando começou e terminou. Para etapas de revisão humana, externalRef* aponta para o registro externo.
"steps": [
{
"stepId": "preEdit",
"type": "action",
"status": "completed",
"errorMessage": null,
"costUsd": 0.0012,
"createdAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:02.000Z"
},
{
"stepId": "localize",
"type": "action",
"status": "completed",
"errorMessage": null,
"costUsd": 0.0184,
"createdAt": "2026-03-16T10:30:02.000Z",
"completedAt": "2026-03-16T10:30:05.000Z"
}
]Uma entrada failed aqui não necessariamente faz o job falhar. Quando uma etapa não crítica falha, o registro steps[] dela aparece como failed, a mesma falha também aparece no nível superior do job em warnings, e o job ainda assim chega a completed_with_warnings com outputData completo. O formato completo do registro — cada campo, cada stepId, a semântica de completed/failed/skipped — fica em uma única página canônica: Observe pipeline runs. Esta página mostra onde encontrá-lo em um job; aquela página define a especificação.
Lendo um job concluído#
Um consumidor típico faz a ramificação com base em status, grava outputData em caso de sucesso e registra errorMessage em caso de falha. A chamada pronta para copiar e colar abaixo retorna o payload mostrado acima.
const jobId = "ljb_A1b2C3d4E5f6G7h8";
const response = await fetch(`https://api.lingo.dev/jobs/localization/${jobId}`, {
headers: { "X-API-Key": process.env.LINGO_API_KEY },
});
const job = await response.json();
switch (job.status) {
case "completed":
case "completed_with_warnings":
// outputData is populated; warnings may carry non-critical stage failures
await db.content.update({
where: { id: job.outputData.id },
data: { [`content_${job.targetLocale}`]: job.outputData },
});
if (job.warnings.length) console.warn(job.targetLocale, job.warnings);
break;
case "failed":
console.error(`${job.targetLocale} failed: ${job.errorMessage}`);
break;
default:
// queued or processing - nothing to read yet; also catches future states
break;
}Polling vs push
Este endpoint faz uma leitura pontual. Para a maioria dos jobs, o engine leva de 2 a 8 segundos por idioma, então, se você fizer polling, um intervalo de 2 segundos é um bom ponto de partida. Para evitar polling por completo, registre um webhook e busque o job apenas quando ele informar que o idioma foi concluído, ou acompanhe o grupo inteiro via WebSocket. De qualquer forma, um GET final aqui é a leitura canônica de outputData.
Quando este endpoint retorna um erro — um jobId desconhecido, uma chave ausente — ele segue o modelo padrão de erro JSON. Consulte Errors and status codes.
