Concepts

Last updated: Apr 1, 2026Section: Integrations

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 include sessionPublicId.
  • 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}/reply with 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 as Authorization: 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 only sessionPublicId to 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"} --- Mailoo apps/web BFF 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.
📚