Lee la salida traducida de un idioma y el registro por etapa de cómo se generó.
Vas a usar esto cuando ya tengas un jobId: viene en el 202 de creación, llega en un webhook o aparece dentro de un grupo de trabajos. El endpoint del grupo te dice cuántos idiomas ya están listos. Este endpoint te dice qué produjo un solo idioma y qué pasó en el camino.
GET /jobs/localization/:jobId¿Recién empiezas con la localización asíncrona? Comienza con la Descripción general.
Esa diferencia es justamente de lo que trata esta página. La respuesta de un grupo es un tablero: conteos y estado por trabajo, explicados en la página del grupo de trabajos. Un trabajo individual es el registro completo de un idioma: el outputData traducido, el status final, cualquier warnings y un rastro en steps[] de cada etapa que ejecutó el pipeline. Cuando estés listo para guardar el texto en alemán en tu base de datos, esta es la llamada que te lo entrega.
Autenticación#
Pasa tu API key en el header X-API-Key. Las claves tienen alcance a nivel de organización y dan acceso a todos los motores de la organización. Consulta Authentication para más detalles.
Respuesta#
El campo outputData refleja la estructura del data de entrada, con cada valor de tipo string traducido y cada valor que no es string (números, booleanos, null) preservado en su lugar. Mismas claves, mismo anidamiento, mismo orden en los arreglos: solo cambian los strings.
{
"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"
}
]
}El bloque metadata de arriba se mantuvo intacto: Dr. Smith y beginner son hojas que no son string y el motor las dejó tal cual. El outputData que recibes de vuelta conserva la misma forma que enviaste, así que el mismo código que armó el payload puede consumir la traducción.
| Campo | Descripción |
|---|---|
id | El ID de este trabajo (ljb_…). Es el valor que pasaste en la ruta. |
groupId | El grupo de trabajos padre (ljg_…) al que pertenece este trabajo. Pásalo al endpoint del grupo de trabajos para ver de una vez todos los idiomas del mismo grupo. |
targetLocale | El idioma BCP-47 al que se tradujo este trabajo; existe un trabajo por cada idioma de destino. Este es el campo sobre el que bifurcas para enrutar outputData a la columna o al archivo correctos. |
status | queued, processing, completed, completed_with_warnings o failed. |
outputData | Contenido traducido que coincide con la estructura de entrada. Está presente cuando status es completed o completed_with_warnings. |
errorMessage | Descripción del error. Está presente cuando status es failed; en cualquier otro caso, null. |
warnings | Fallos no críticos en etapas del pipeline. Cada entrada es { step, message }. Está vacío, salvo que status sea completed_with_warnings. |
callbackStatus | Estado de entrega del webhook: pending, delivered o failed. null si no hay una callback URL configurada. |
createdAt | Cuándo se aceptó el trabajo (la marca de tiempo del 202 que lo creó). |
startedAt | Cuándo el motor empezó a traducir este idioma. Se establece una vez que el trabajo sale de queued. |
completedAt | Cuándo el trabajo llegó a un estado final. Se establece una vez que status es completed, completed_with_warnings o failed. |
steps | Registros de ejecución por etapa. Siempre contiene el paso localize, además de una entrada por cada etapa opcional del pipeline que esté habilitada. La forma completa del registro está en Observe pipeline runs. |
outputData es null hasta que el trabajo termina
Mientras status sea queued o processing, outputData está vacío y errorMessage es null: todavía no hay nada para leer. Lee outputData solo después de que status llegue a completed o completed_with_warnings; si es failed, lee errorMessage en su lugar. Primero bifurca por status y después toca el payload.
Valores de estado del trabajo#
Un trabajo pasa de queued a processing y luego a exactamente un estado final. Bifurca por status antes de leer cualquier otra cosa: te dice qué campos vienen poblados.
| Estado | Significado | Qué leer |
|---|---|---|
queued | Aceptado, pero todavía no empieza. | Todavía nada: haz polling o espera el webhook. |
processing | El motor está traduciendo este idioma. | Todavía nada. |
completed | La traducción terminó y todas las etapas habilitadas se completaron correctamente. | outputData. |
completed_with_warnings | La traducción terminó y outputData está completo, pero falló una etapa no crítica del pipeline. | outputData y luego warnings. |
failed | El trabajo no produjo ninguna traducción. | errorMessage. |
completed_with_warnings igual entrega una traducción
completed_with_warnings no es un fallo leve. Recibes outputData completo: el paso principal de traducción se completó correctamente. Lo que cambió es que una etapa no crítica (por ejemplo, pre-edit o back-translation) no terminó, y cada fallo queda registrado en warnings como { step, message }. Trata la salida como utilizable; trata warnings como una señal de calidad que vale la pena mostrar a quien haga la revisión de las traducciones. Solo failed significa que no hay ninguna traducción para leer.
Maneja valores de estado desconocidos
Los cinco valores de estado de arriba son el contrato actual. Las etapas del pipeline evolucionan, así que trata status como un conjunto abierto: bifurca por los valores que conoces y manda cualquier valor inesperado a un caso por defecto que lea outputData si está presente y, si no, lo registre. Un switch sin fallback es la línea que se rompe el día en que aparece un estado nuevo.
El arreglo steps#
steps[] es el rastro por etapa detrás de un solo trabajo: un registro por cada etapa que ejecutó el motor, en orden. Cada trabajo incluye al menos el paso localize, porque la traducción principal siempre se ejecuta. Cada etapa opcional del pipeline que habilites agrega un registro más. Así, un trabajo sin etapas extra muestra un solo paso localize; uno con pre-edit y back-translation habilitados muestra tres.
Esto es lo que hace que un trabajo sea auditable y no una caja negra. No tienes que asumir que una etapa se ejecutó: puedes leer su registro, qué etapa fue (stepId), si completed, failed o fue skipped, cuánto costó (costUsd) y cuándo empezó y terminó. En las etapas de revisión humana, externalRef* apunta al 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"
}
]Una entrada failed aquí no necesariamente hace fallar el trabajo. Cuando falla una etapa no crítica, su registro steps[] aparece como failed, el mismo fallo también aparece en el warnings de nivel superior del trabajo, y aun así el trabajo llega a completed_with_warnings con outputData completo. La forma completa del registro —cada campo, cada stepId, y la semántica de completed/failed/skipped— vive en una sola página canónica: Observe pipeline runs. Esta página te muestra dónde encontrarlo dentro de un trabajo; esa página lo define.
Leer un trabajo completado#
Un consumidor típico bifurca por status, escribe outputData cuando hay éxito y registra errorMessage cuando hay error. La llamada lista para copiar y pegar de abajo devuelve el payload que se muestra arriba.
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 te da una lectura de un momento puntual. Para la mayoría de los trabajos, el motor tarda entre 2 y 8 segundos por idioma, así que, si haces polling, empezar con un intervalo de 2 segundos es razonable. Si quieres evitar el polling por completo, registra un webhook y consulta el trabajo solo cuando te avise que el idioma ya está listo, o sigue todo el grupo por WebSocket. De cualquier forma, un GET final aquí es la lectura canónica de outputData.
Cuando este endpoint devuelve un error —un jobId desconocido, una clave faltante— sigue el modelo estándar de errores JSON. Consulta Errors and status codes.
