|
Documentación
Agenda una demoPlataforma
PlataformaMCPCLIAPI
Flujos de trabajo
GuíasRegistro de cambios

Bienvenida

  • Descripción general
  • Autenticación
  • Errores y códigos de estado
  • Firmas de webhook

Localización

  • Descripción general
  • Crear trabajos
  • Bloquea las claves no traducibles
  • Monitorear un grupo de trabajos
  • Obtener un trabajo
  • Listar trabajos
  • Entrega de webhooks
  • Progreso en tiempo real (WebSocket)

Pipeline

  • Descripción general
  • Edición con IA previa a la localización
  • Revisión humana
  • evaluación de IA (post-edición)
  • Reescribe para que suene natural
  • Verificación de retrotraducción
  • Configura el pipeline
  • Ver ejecuciones del pipeline

Aprovisionamiento

  • Descripción general
  • Crear un trabajo de aprovisionamiento
  • Tipos de fuente
  • Lo que extrae la IA
  • Entrega de webhooks
  • Progreso en vivo (WebSocket)

Síncrono

  • Localize
  • Recognize

Gestión del motor

  • Sugerencias del motor

Entrega de webhooks

Creaste un grupo de trabajos y recibiste un 202 en milisegundos. Las traducciones ahora se están ejecutando en segundo plano, un trabajo por idioma. Podrías consultar cada trabajo hasta que termine, pero seguramente no quieres montar un ciclo de sondeo solo para enterarte de que alemán ya está listo. Lo que quieres es que tu servidor se entere en el momento en que cada idioma quede listo.

Para eso está el webhook. Cuando pasas un callbackUrl al crear trabajos, Lingo envía el resultado por POST a esa URL en cuanto cada trabajo alcanza un estado terminal: un POST por idioma, justo cuando queda listo. Si un idioma se traduce correctamente, llega como translation.completed con los datos. Si un idioma falla, llega como translation.failed con el error. Te enteras de cualquier forma, por idioma, sin tener que preguntar.

Esta página cubre los dos payloads y cómo manejarlos. La entrega va firmada y tiene reintentos; esa mecánica se comparte con provisioning y vive en la página de verificación de firma del webhook, enlazada en cada punto donde la vas a necesitar.

En esta página

  • Cómo funciona la entrega
  • El payload de completado
  • El payload de error
  • Cómo manejar un webhook
  • Cuándo la entrega no es la herramienta adecuada

Cómo funciona la entrega#

Cada idioma de un grupo es un trabajo independiente. En cuanto uno alcanza un estado terminal, su resultado se entrega por separado a tu callbackUrl; Lingo no espera al idioma más lento ni agrupa todo en una sola llamada. Catorce idiomas de destino significan hasta catorce POST, que van llegando a medida que termina cada idioma, en el orden en que terminen.

Configura el destino por solicitud con callbackUrl cuando crees el grupo de trabajos, o define un valor predeterminado de la organización en el dashboard que todos los grupos heredan. Un callbackUrl por solicitud anula el valor predeterminado de la organización para ese grupo.

Solo HTTPS

callbackUrl debe usar HTTPS. Una URL HTTP se rechaza con un 400 cuando creas el trabajo: el webhook va firmado, y enviar un payload firmado sobre texto sin cifrar le quita todo el sentido.

Hay dos formas de payload que viajan por la red, distinguidas por su campo type: translation.completed y translation.failed. Ambas identifican el trabajo y el grupo al que pertenecen, además del idioma que traen, así que un solo handler puede enrutar según type y actualizar el registro correcto.

Maneja con elegancia los tipos de evento desconocidos

Hoy por la red viajan translation.completed y translation.failed. Toma ese conjunto como abierto: maneja los tipos que conoces e ignora el resto, para que un tipo de evento futuro no rompa un handler ya desplegado.

El payload de completado#

Cuando un trabajo termina correctamente, el payload trae el data traducido: la misma forma que obtendrías al consultar el trabajo, pero enviada a ti en lugar de tener que sondearla. El data refleja la estructura que enviaste: cada string traducido, cada valor que no es string (números, booleanos, null) preservado y la anidación intacta.

json
{
  "type": "translation.completed",
  "jobId": "ljb_A1b2C3d4E5f6G7h8",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "sourceLocale": "en",
  "targetLocale": "de",
  "data": {
    "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" }
  }
}
CampoDescripción
typetranslation.completed
jobIdEl trabajo que terminó (prefijo ljb_)
groupIdEl grupo al que pertenece (prefijo ljg_)
sourceLocaleEl idioma de origen que enviaste
targetLocaleEl idioma al que se tradujo este payload
dataContenido traducido, con la misma estructura del data que enviaste

Un trabajo que produce output no es un fallo; por eso, un trabajo que terminó como completed_with_warnings (se produjo output, pero una etapa opcional del pipeline no se completó) se entrega como translation.completed, con un data utilizable. El webhook te avisa que el idioma está listo; las advertencias por paso que explican qué ocurrió viven en el trabajo individual, que recuperas por jobId cuando las necesites.

El payload de error#

Un idioma puede fallar: un modelo puede agotar el tiempo de espera, o todos los modelos configurados pueden no estar disponibles. Cuando un trabajo llega a failed, igual recibes la notificación. El tipo de payload es translation.failed y trae un string error en lugar de data:

json
{
  "type": "translation.failed",
  "jobId": "ljb_C3d4E5f6G7h8I9j0",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "sourceLocale": "en",
  "targetLocale": "ja",
  "error": "Model timeout after 30 seconds"
}
CampoDescripción
typetranslation.failed
jobIdEl trabajo que falló
groupIdEl grupo al que pertenece
sourceLocaleEl idioma de origen que enviaste
targetLocaleEl idioma que falló
errorDescripción del fallo en lenguaje claro

El fallo se limita a un solo idioma. Si enviaste de, fr y ja, un fallo en ja se entrega como su propio POST translation.failed, mientras que de y fr llegan como translation.completed; las traducciones al alemán y al francés se entregan de todos modos. El estado de fallo parcial del grupo refleja esa mezcla. Para recuperar el idioma que falló, envía un trabajo nuevo solo para ese idioma con una clave de idempotencia nueva.

Cómo manejar un webhook#

La primera reacción de cualquier lector escéptico acá es la correcta: mi handler hace trabajo real —una escritura en base de datos, una invalidación de caché, una distribución a clientes conectados—, así que ¿eso no va a mantener la conexión abierta el tiempo suficiente como para que el webhook expire?

Sí, así que no hagas esperar a Lingo. Devuelve 200 primero y procesa después. Confirma la recepción de inmediato y deja el trabajo real para después de enviar la respuesta. Un handler que responde rápido mantiene la entrega saludable; un handler que bloquea por trabajo aguas abajo provoca un reintento que nunca necesitó.

javascript
app.post("/webhooks/translations", verifyWebhook, async (req, res) => {
  // Acknowledge first - one POST per locale, the moment it lands.
  res.status(200).send("ok");

  const { type, jobId, groupId, targetLocale, data } = req.body;

  if (type === "translation.completed") {
    await db.content.update({
      where: { groupId },
      data: { [`content_${targetLocale}`]: data },
    });

    // Advance your own progress model - your UI can poll this or receive it over SSE.
    await db.translationProgress.increment({
      where: { groupId },
      data: { completedLanguages: { increment: 1 } },
    });
  }

  if (type === "translation.failed") {
    console.error(`Translation failed: ${jobId} (${targetLocale})`, req.body.error);
  }
});

El middleware verifyWebhook es la única pieza que esta página no define. Cada entrega va firmada según la especificación Standard Webhooks, así que no es un esquema que tengas que descifrar por tu cuenta. Cómo verificarla —y el calendario de reintentos detrás de una respuesta no 2xx— está documentado por completo en verificación de firma del webhook, compartido con provisioning. Conecta ese middleware antes de confiar en cualquier payload: un body sin verificar es un body no autenticado.

Verifica antes de confiar en el body

Tu endpoint es una URL pública; cualquiera puede hacerle POST. Verifica la firma contra el body sin procesar de la solicitud antes de actuar sobre cualquier payload. El cómo —headers, el HMAC, el secreto whsec_— está en la página de verificación de firma.

Cuándo la entrega no es la herramienta adecuada#

El webhook es una comodidad de tipo push, no el sistema de registro. Hay dos casos en los que conviene usar otra cosa, y ambos están a un clic de distancia.

Si tu endpoint estaba caído cuando se entregó un resultado, la plataforma reintenta; y si se agotan todos los reintentos, el resultado no se pierde. Sigue siendo recuperable por jobId; el callbackStatus del trabajo registra si el envío por push finalmente tuvo éxito. El calendario de reintentos en sí está en la página de firma y entrega. El webhook te ahorra un ciclo de sondeo en el caso común; el registro del trabajo siempre está ahí por debajo para el menos común.

Y si lo que quieres es progreso en vivo en una UI —un contador que pase de 3 de 14 a 4 de 14 a medida que van quedando listos los idiomas, en lugar de un callback por idioma a tu servidor—, entonces lo que necesitas es el WebSocket del grupo de trabajos, no el webhook.

Progreso en vivo (WebSocket)
Lleva el progreso del grupo a una UI con snapshots de estado completo, en lugar de callbacks por idioma a tu servidor.
Verificación de firma del webhook
Verifica la firma, revisa los headers y maneja el calendario de reintentos: compartido entre todas las entregas de webhook.
Obtener un solo trabajo
Recupera cualquier resultado por jobId, incluidas las advertencias: la fuente de verdad detrás de cada entrega.

¿Te resultó útil esta página?

Max PrilutskiyMax Prilutskiy·Actualizado hace 12 días·6 min de lectura