Concepts
Chat widget (JSBOX)
The JSBOX integration type powers website chat: visitors send messages that appear in your Mailoo dashboard. You can reply from the chat console; visitors see updates over WebSocket or polling.
::: {.contents local=""} :::
Concepts
- Integration type:
JSBOX(created in the dashboard or via the public API with an API key). - Sessions: Each visitor thread is a chat session (opaque
sessionPublicId). The first message creates a session; later messages includesessionPublicId. - API key: Required for server-side calls to Mailoo webhooks (your BFF, backend, or automation). Never put the API key in browser JavaScript.
Public API (X-API-Key)
Restricted keys can include:
webhook.chat-integration-create---POST /api/v1/webhooks/chat/{projectUid}/integrations(create a JSBOX integration).chat.send-message--- chat messages, session history, and chat status under/api/v1/webhooks/chat/....
Create a JSBOX integration
curl -X POST "http://localhost:4077/api/v1/webhooks/chat/proj_1/integrations" \\
-H "X-API-Key: YOUR_KEY" \\
-H "Content-Type: application/json" \\
-d '{"name":"Support chat","config":{"welcomeMessage":"Hi!","allowedOrigins":["https://example.com"]}}'
Send a visitor message (scoped to project + integration):
curl -X POST "http://localhost:4077/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"}'
List messages in a session (for server/BFF polling):
GET /api/v1/webhooks/chat/{projectUid}/{integrationId}/sessions/{sessionPublicId}/messages?since=ISO8601
Chat integration status
GET /api/v1/webhooks/chat/{projectUid}/{integrationId}/status
Legacy path (integration id only): POST /api/v1/webhooks/messages/{integrationId} still exists but requires chat.send-message and a JSBOX integration.
Dashboard (Bearer JWT)
- Sessions:
GET /api/v1/chat/{integrationId}/sessions - History:
GET /api/v1/chat/{integrationId}/sessions/{sessionPublicId}/messages - Owner reply:
POST /api/v1/chat/{integrationId}/sessions/{sessionPublicId}/replywith JSON{"content":"..."}.
The web app proxies these through its BFF under the same paths (with session auth).
WebSocket
In Mailoo apps/web, the browser WS host is not a NEXT_PUBLIC_* build-time variable: the server resolves it at runtime (MAILOO_CHAT_WS_ORIGIN, else chat/API base env --- see getMailooChatWebSocketOrigin).
- Owner (dashboard):
/api/v1/chat/ws?integrationId=...&token=<JWT>--- use your Keycloak access token (same asAuthorization: Bearer). In development, the dev bypass token is also accepted when configured. - Visitor:
/api/v1/chat/visitor-ws?projectUid=...&integrationId=...&sessionPublicId=...--- no API key; the session must already exist (created by posting a message). Prefer exposing onlysessionPublicIdto the browser and validating on your BFF when possible.
For architecture details, event payloads, reverse proxy (wss), and multi-replica caveats, see chat-websocket-production{.interpreted-text role="doc"}.
CORS and allowedOrigins
Browser calls to Mailoo webhooks send an Origin header. Configure allowed origins (and optional domain) on the JSBOX integration config, same pattern as form integrations.
See also
chat-widget-nextjs-example{.interpreted-text role="doc"} --- Mailooapps/webBFF pattern and env variables.chat-websocket-production{.interpreted-text role="doc"} --- WebSocket behaviour and production API exposure.../../api/authentication{.interpreted-text role="doc"} --- API keys and scopes.