Widget de chat (JSBOX)

Última actualización: Oct 12, 2026Sección: Integraciones

El tipo de integración JSBOX alimenta el chat del sitio web: los visitantes envían mensajes que aparecen en tu panel de control de Mailoo. Puedes responder desde la consola de chat; los visitantes ven las actualizaciones mediante WebSocket o polling.

::: {.contents local=""} :::

Conceptos

  • Tipo de integración: JSBOX (creado en el panel de control o mediante la API pública con una clave API).
  • Sesiones: Cada hilo de visitante es una sesión de chat (sessionPublicId opaco). El primer mensaje crea una sesión; los mensajes posteriores incluyen sessionPublicId.
  • Clave API: Obligatoria para llamadas del lado del servidor a los webhooks de Mailoo (tu BFF, backend o automatización). Nunca pongas la clave API en JavaScript del navegador.

API pública (X-API-Key)

Las claves restringidas pueden incluir:

  • webhook.chat-integration-create --- POST /api/v1/webhooks/chat/{projectUid}/integrations (crear una integración JSBOX).
  • chat.send-message --- mensajes de chat, historial de sesión y estado de chat bajo /api/v1/webhooks/chat/....

Crear una integración JSBOX

curl -X POST "https://api.mailoo.app/api/v1/webhooks/chat/proj_1/integrations" \\
     -H "X-API-Key: YOUR_KEY" \\
     -H "Content-Type: application/json" \\
     -d '{"name":"Support chat","config":{"allowedOrigins":["https://example.com"]}}'

Enviar un mensaje de visitante (limitado a proyecto + integración):

curl -X POST "https://api.mailoo.app/api/v1/webhooks/chat/{projectUid}/{integrationId}/messages" \\
     -H "X-API-Key: YOUR_KEY" \\
     -H "Content-Type: application/json" \\
     -H "Origin: https://your-site.com" \\
     -d '{"content":"Hello","sessionPublicId":"optional-if-continuing"}'

Listar mensajes en una sesión (para polling servidor/BFF):

GET /api/v1/webhooks/chat/{projectUid}/{integrationId}/sessions/{sessionPublicId}/messages?since=ISO8601

Estado de la integración de chat

GET /api/v1/webhooks/chat/{projectUid}/{integrationId}/status

Ruta legada (solo id de integración): POST /api/v1/webhooks/messages/{integrationId} sigue existiendo pero requiere chat.send-message y una integración JSBOX.

Los webhooks públicos de chat comparten el rate limit de la clave API. Cuando se supera, Mailoo responde HTTP 429. El widget @mailoo/chat clasifica eso (y fallos de gateway/red) y muestra un panel de indisponibilidad en lugar del texto crudo de la API --- el host debe pasar unavailableAction (ver chat-widget-nextjs-example{.interpreted-text role="doc"}).

Panel de control (JWT Bearer)

  • Sesiones: GET /api/v1/chat/{integrationId}/sessions --- status=OPEN|PENDING|CLOSED opcional y assignedUserId=<userId> o assignedUserId=unassigned.
  • Historial: GET /api/v1/chat/{integrationId}/sessions/{sessionPublicId}/messages
  • Respuesta del propietario: POST /api/v1/chat/{integrationId}/sessions/{sessionPublicId}/reply con JSON {"content":"..."}.
  • Asignar / cerrar: PATCH /api/v1/chat/{integrationId}/sessions/{sessionPublicId} con {"assignedUserId":"<userId>"|null} (solo miembros del proyecto) o {"action":"close"}.

Las sesiones son OPEN, PENDING o CLOSED. Ajustes del widget JSBOX (config.chatWidget):

  • Autorespuesta --- el primer mensaje del visitante en una sesión nueva envía autoresponder.message; expectedReplyHours opcional pasa el estado a PENDING hasta que un operador responda.
  • Plantillas de respuesta --- replyTemplates (no plantillas de campaña FORM); la consola las inserta en el cuadro de respuesta.
  • Seguimiento al cerrar --- con action: close, se envían closeFollowUp.message y/o closeFollowUp.reviewUrl. Mensajes posteriores del visitante en una sesión cerrada devuelven 409.
  • Agente IA opcional --- config.chatWidget.agent (enabled, name, imageMediaId opcional, kbIntegrationId Blog del mismo proyecto, markdown instructions / kbDigestPrompt / kbArticlePrompt, kbFiles). Si está activo, el agente aparece primero en el equipo (id jsbox_chat_agent). La API antepone instructions, rellena las plantillas y llama a Wednesday en segundo plano con un digest de KB (solo título + slug); el cuerpo del artículo vía KB_REQUEST:<slug>. Los archivos KB se guardan en S3 y aún no se inyectan al modelo. El widget no habla con Wednesday. Respuestas OUTBOUND jsbox_chat_agent con senderName = nombre visible. Asignar detiene el agente. El agente también puede transferir a un humano con HANDOFF_TO_HUMAN: (texto al visitante más brief para operadores); Mailoo fija handedOffAt, estado PENDING, guarda el brief como OUTBOUND metadata.source: jsbox_chat_agent_handoff (solo dashboard) y omite más turnos del agente. Hace falta WEDNESDAY_BASE_URL (dev: http://127.0.0.1:4080).
  • MCP / ajustes de agente --- GET/PATCH /api/v1/chat/{projectUid}/integrations/{integrationId}/settings (ámbito chat.manage o token MCP) lee/actualiza la misma config saneada del widget y devuelve conteos lifetime de mensajes y sesiones (sin lista de sesiones ni cuerpos). Herramienta MCP: manage_jsbox_integration_settings (ver mailoo-mcp{.interpreted-text role="doc"}). Skill de agente (reglas mínimas): configure-chat-mcp{.interpreted-text role="doc"}.

La aplicación web las proxea a través de su BFF bajo las mismas rutas (con autenticación de sesión).

WebSocket

En un host Next.js usando @mailoo/chat, el origen WebSocket del navegador no es una variable de tiempo de compilación NEXT_PUBLIC_*: el servidor lo resuelve en tiempo de ejecución (MAILOO_CHAT_WS_ORIGIN, sino entorno base de chat/API --- consulta getMailooChatWebSocketOrigin).

  • Propietario (panel): /api/v1/chat/ws?integrationId=...&token=<JWT> --- usa el mismo token de acceso que Authorization: Bearer.
  • Visitante: /api/v1/chat/visitor-ws?projectUid=...&integrationId=...&sessionPublicId=... --- sin clave API; la sesión debe existir ya (creada al enviar un mensaje). Prefiere exponer solo sessionPublicId al navegador y validar en tu BFF cuando sea posible.

Para detalles de arquitectura, payloads de eventos, proxy inverso (wss) y consideraciones multi-réplica, consulta chat-websocket-production{.interpreted-text role="doc"}.

Panel (detalle de integración)

En la página de la integración JSBOX, los propietarios del proyecto usan pestañas:

  • Widget --- colores de marca, texto de bienvenida, URL de privacidad, posición del launcher (cuatro esquinas más middle-left / middle-right; por defecto bottom-right) y temas.
  • Respuestas y automatización --- visibilidad de operadores, autoresponder, plantillas de respuesta y seguimiento al cerrar.
  • Agente IA --- ajustes solo del propietario: interruptor, nombre, avatar opcional, Blog KB, ventanas markdown de instrucciones y subida de archivos KB (S3). Los editores pueden abrir la pestaña; solo el propietario guarda. Si está activo, el agente está en el equipo del widget y en Setup → Operators (sin checkbox). El chat flotante de mailoo.app es esta misma JSBOX; el seed de desarrollo activa el agente con nombre, Blog KB y plantillas de prompt (Wednesday + WEDNESDAY_BASE_URL).
  • Conexión y ajustes --- biblioteca de imágenes, claves API, snippet de entorno del servidor y eliminación. El config almacenado está detrás de Ver JSON de configuración (diálogo de referencia formateado), no como bloque siempre visible.

JSBOX no tiene pestaña Products/contenido: el estado, el recuento de mensajes y la última actividad permanecen en la cabecera. Los editores ven esas métricas de cabecera, Conexión y ajustes y la pestaña Agente IA (interruptor desactivado). Los editores de widget/respuestas siguen siendo solo del propietario.

CORS y allowedOrigins

Las llamadas del navegador a los webhooks de Mailoo pueden enviar una cabecera Origin. Opcionalmente configura orígenes permitidos en la integración JSBOX. Si la lista está vacía, no se verifica Origin (la clave API sigue siendo obligatoria). El campo legado domain en la configuración almacenada permanece como respaldo CORS para filas antiguas pero ya no se recopila en el panel de control.

La posición del launcher se guarda en config.chatWidget.position y se devuelve en el endpoint público widget-config. La ruta de host por defecto (resolveMailooChatHostConfig + MailooSiteChatShell) la aplica siempre vía widgetConfig. Un prop position explícito en MailooSiteChatWidget sigue teniendo prioridad si se define.

Consulta también

  • chat-widget-nextjs-example{.interpreted-text role="doc"} --- patrón BFF de Next.js y variables de entorno
  • chat-websocket-production{.interpreted-text role="doc"} --- comportamiento WebSocket y notas de producción
  • OpenAPI: https://api.mailoo.app/docs/v1