Creaste un trabajo de aprovisionamiento y recibiste un ID de trabajo pjb_ y un ID de motor eng_ en cuestión de milisegundos. El motor ya se puede usar, pero todavía se sigue completando: un agente de IA está rastreando tus fuentes y escribiendo voces de marca, elementos del glosario e instrucciones en él. Mientras eso sucede, quieres mostrar el avance: una línea tipo "Rastreando tu guía de estilo… configurando el motor… listo", como en un asistente de instalación, en vez de un spinner que no dice nada.
El WebSocket te da exactamente ese flujo. Te conectas al trabajo y el servidor envía un snapshot del estado actual; luego, un evento provisioning.progress cada vez que el flujo de trabajo pasa a una nueva etapa. Y como el servidor envía el estado actual al conectarte y cierra un trabajo terminado inmediatamente después, puedes conectarte en cualquier momento, incluso después de que termine: no hay ninguna ventana que tengas que alcanzar.
GET /jobs/provisioning/:jobId/wsEl jobId es el valor pjb_ de la llamada create. ¿Es tu primera vez con el aprovisionamiento asíncrono? Empieza por la Descripción general para entender el modelo mental.
En esta página
- Tipos de mensaje
- Snapshot al conectar
- Eventos de progreso
- Conectarte después de que termine el trabajo
- Integrarlo en tu UI
- Mantén tu clave de API del lado del servidor
Tipos de mensaje#
Hay dos tipos de mensajes que viajan por el socket. El primero llega una sola vez, al conectarte; el segundo llega repetidamente, a medida que avanza el trabajo.
| Tipo | Cuándo | Campos clave |
|---|---|---|
provisioning.snapshot | En la conexión inicial | jobId, status, errorMessage |
provisioning.progress | Cuando cada paso del flujo de trabajo comienza o termina | jobId, step, detail |
Este es un flujo de actividad, no un flujo de resultados: te dice en qué etapa va el trabajo y si falló, no qué registros creó la IA. El resumen de todo lo aprovisionado —los IDs de voz de marca, glosario e instrucciones— llega por separado, en el webhook de finalización o consultando el trabajo una vez que termine. Usa el socket para la barra de progreso; usa el webhook para la carga útil.
Snapshot al conectar#
En cuanto te conectas, el servidor lee el estado actual del trabajo en la base de datos y lo envía. No hace falta que llegue primero un evento de progreso: el snapshot se sostiene por sí solo.
{
"type": "provisioning.snapshot",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"status": "in_progress",
"errorMessage": null
}| Campo | Descripción |
|---|---|
status | in_progress, completed o failed. |
errorMessage | La descripción del fallo cuando status es failed; de lo contrario, null. |
El snapshot es el único mensaje que tienes garantizado recibir. Si el trabajo sigue en ejecución, recibirás eventos de progreso después; si el trabajo ya terminó, recibirás el snapshot y nada más (consulta más abajo).
Eventos de progreso#
A medida que avanza el flujo de trabajo, el servidor emite un evento provisioning.progress cada vez que entra en una nueva etapa. Cada evento indica el step y trae un detail legible para humanos.
{
"type": "provisioning.progress",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"step": "crawling",
"detail": "Crawling source URLs..."
}step | Cuándo | Ejemplo de detail |
|---|---|---|
crawling | Se están obteniendo las URLs de origen | "Crawling source URLs..." o "Retrying crawl (attempt 2)..." |
configuring | El agente de IA está analizando el contenido y escribiendo la configuración del motor | "AI agent analyzing content and configuring engine..." o "Retrying configuration (attempt 2)..." |
completed | El trabajo terminó correctamente | "Provisioning complete" |
failed | El trabajo falló | Un mensaje de error que describe la falla |
Un reintento no es una falla
Los pasos crawling y configuring pueden activarse más de una vez: si hay un error transitorio al obtener o analizar, se reintenta, y ese reintento aparece como un evento de progreso con un detail como "Retrying crawl (attempt 2)...". Eso significa que el trabajo se está recuperando, no que esté fallando. Trata solo el paso failed como terminal; su detail contiene la razón real.
Maneja los pasos que no reconozcas
Con el tiempo pueden agregarse nuevos valores de step. Haz switch sobre las etapas que conoces, trata completed y failed como las dos que cierran el socket, e ignora cualquier otra como informativa: un cliente compatible hacia adelante sigue funcionando sin necesidad de actualizarse.
Conectarte después de que termine el trabajo#
La gran pregunta con cualquier socket de progreso es qué pasa si te conectas tarde: después de que terminó el rastreo, después de que un despliegue volvió a conectar la pestaña, después de que el trabajo ya falló. Aquí, la respuesta está integrada en cómo funciona el snapshot.
Si el trabajo ya llegó a completed o failed, el servidor envía el snapshot con ese status final (y errorMessage, si falló) y cierra la conexión de inmediato. No hay eventos de progreso para reproducir, porque el estado final es el snapshot. Un trabajo que sigue en curso mantiene la conexión abierta y transmite el progreso; un trabajo terminado te entrega el resultado y corta la conexión.
De cualquier forma, el primer mensaje te dice dónde están las cosas. Conéctate en cualquier momento, incluso después de que termine: no puedes conectarte ni demasiado pronto ni demasiado tarde.
Integrarlo en tu UI#
Abre el socket con el ID de trabajo pjb_, lee el snapshot para establecer el estado inicial, luego actualiza con cada evento de progreso y cierra cuando el trabajo llegue a completed o failed:
import WebSocket from "ws";
const jobId = "pjb_A1b2C3d4E5f6G7h8";
const ws = new WebSocket(
`wss://api.lingo.dev/jobs/provisioning/${jobId}/ws`,
{ headers: { "X-API-Key": process.env.LINGO_API_KEY } }
);
ws.on("message", (raw) => {
const event = JSON.parse(raw);
switch (event.type) {
case "provisioning.snapshot":
console.log(`status: ${event.status}`);
break;
case "provisioning.progress":
console.log(`${event.step}: ${event.detail}`);
if (event.step === "completed" || event.step === "failed") {
ws.close();
}
break;
}
});Pruébalo con un trabajo que rastree sin problemas y vaya mostrando la configuración paso a paso:
status: in_progress
crawling: Crawling source URLs...
configuring: AI agent analyzing content and configuring engine...
completed: Provisioning completeEse es todo el recorrido en pantalla: el trabajo arranca en in_progress, ves cómo rastrea y luego configura, y completed te indica que el motor quedó completamente aprovisionado. El mismo ciclo también funciona en una conexión tardía: un trabajo terminado envía un solo snapshot con su status final y el socket se cierra, así que el código que maneja la ejecución en vivo también maneja la repetición sin necesitar un caso especial.
Mantén tu clave de API del lado del servidor#
El socket se autentica con tu clave de API: la misma clave con alcance a nivel de organización que usan los endpoints REST. Esa clave da acceso a todos los motores de tu organización, así que el navegador es el lugar equivocado para abrir la conexión: cualquiera que vea el código fuente podría verla.
Conéctate desde tu backend, no desde el navegador
Abre el WebSocket desde tu servidor, donde la clave ya vive, y luego reenvía el progreso al navegador por tu propio canal: un WebSocket o un flujo de eventos enviados por el servidor que tú controles. Tu frontend muestra el motor mientras se configura; tu clave nunca sale de tu infraestructura.
Esto refleja el modelo de webhook: la conexión que toca Lingo.dev corre del lado del servidor, y lo que llega al usuario es lo que tu propia app decida reenviar.
Dónde encaja esto#
El WebSocket es la vista en vivo: está vinculado a un solo trabajo y se cierra cuando ese trabajo termina. Si quieres un registro duradero del resultado, de servidor a servidor, que sobreviva al cierre de una pestaña o a un despliegue, combínalo con el webhook de finalización: el socket impulsa la barra de progreso mientras el trabajo está en pantalla, y el webhook entrega el resumen de todo lo que creó la IA en cuanto llega. Conecta ambos desde la misma llamada create.
