Chatbot WebSocket API (Live chat)

WebSocket API

Gebruik de WebSocket API voor realtime live chat: directe berichtbezorging, typindicatoren, aanwezigheid, automatische vertaling en sessielevenscyclus. Dezelfde socket voedt bezoekerswidgets en het agent-dashboard, zodat je een aangepaste agent-console kunt bouwen of live chat vanuit je eigen backend kunt aansturen.

Eindpunt

wss://webchatagent.com/api/livechat

Al het verkeer is JSON. Je verstuurt client:*-gebeurtenissen; de server stuurt livechat:*-gebeurtenissen terug. Elk bericht bevat een type-veld.

Verbindingsrollen

Wanneer je deelneemt, declareer je een rol met het as-veld:

RolBeschrijving
userEen websitebezoeker in een chat.
adminEen menselijke agent die livechatsessies beheert.
widgetDe ingesloten chatwidget in monitoringmodus (vóór een overname).

De rol bepaalt wat je ontvangt: admin-clients ontvangen de volledige berichtengeschiedenis en events die alleen voor admins zijn bedoeld; user-clients ontvangen alleen nieuwe live-events (bezoekers laden hun eigen geschiedenis via het REST history endpoint, niet via de socket).

Korte flow

  1. Open de socket en verstuur client:join met je chatbotId, sessionId en as.
  2. De server antwoordt met { "type": "livechat:status", "ok": true } om de deelname te bevestigen. Admins ontvangen vervolgens de berichtengeschiedenis en een actuele livechat:status-momentopname.
  3. Verstuur client:message om te plaatsen; ontvang livechat:message voor elk nieuw bericht.
  4. Verstuur client:typing / ontvang livechat:typing voor typindicatoren.
  5. Sluit af met client:end, of ontvang livechat:ended wanneer de andere partij sluit.

Client-events (die jij verstuurt)

client:join

Het eerste event na het verbinden. Neemt deel aan de sessieruimte (en, voor admins, de chatbotruimte).

{
  "type": "client:join",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "as": "user",
  "lang": "en",
  "translateEnabled": true,
  "retranslateBacklog": false
}
VeldTypeVerplichtBeschrijving
chatbotIdstringJaDe UUID van je chatbot. Voor een admin die alle bots monitort, zorgt de speciale waarde "all" voor deelname zonder een specifieke ruimte.
sessionIdstringJaHet chatsessie-ID.
asstringJauser, admin of widget.
langstringNeeVoorkeurstaalcode (bijv. en, de, fr). Stelt het vertaaldoel in.
translateEnabledbooleanNeeSchakel automatische vertaling in voor deze sessie (standaard: ingeschakeld).
retranslateBacklogbooleanNeeVertaal bestaande backlog-berichten opnieuw naar lang bij het deelnemen (admin).

client:message

Plaats een bericht in de sessie. De server slaat het op, vertaalt het indien ingeschakeld, en zendt livechat:message uit.

{
  "type": "client:message",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "sender": "user",
  "content": "I need help with my order",
  "lang": "en"
}
VeldTypeVerplichtBeschrijving
chatbotIdstringJaDe UUID van je chatbot.
sessionIdstringJaHet chatsessie-ID.
senderstringJauser of admin.
contentstringJaDe berichttekst. Een lege of ontbrekende content wordt genegeerd.
langstringNeeTaalsuggestie van het bericht voor vertaling.

Het eerste admin-bericht in een sessie die wachtend is opent deze (status → open) en voegt automatisch een "agent toegetreden"-systeembericht in.

client:typing

Zend een typindicator uit naar iedereen in de sessie.

{
  "type": "client:typing",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "sender": "user",
  "isTyping": true
}

client:meta

Werk sessiemetadata (huidige pagina) bij zodat agents zien waar de bezoeker zich bevindt.

{
  "type": "client:meta",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "pageUrl": "https://example.com/pricing",
  "pageTitle": "Pricing - Example",
  "referrer": "https://google.com",
  "browserLanguage": "en-US"
}

client:agent_takeover

Admin neemt proactief een AI-sessie over (zet deze op open / human). Alleen voor admins.

{
  "type": "client:agent_takeover",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID"
}

client:end

Beëindig de sessie.

{
  "type": "client:end",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "reason": "resolved"
}

client:widget_open / client:widget_close

Verzonden door de widget om een actieve sessie te registreren/af te melden voor zichtbaarheid door admins (dit vult livechat:widget_sessions).

{
  "type": "client:widget_open",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "pageUrl": "https://example.com",
  "pageTitle": "Home",
  "browserLanguage": "en-US"
}

Server-events (die jij ontvangt)

livechat:status

Twee vormen: een eenvoudige { "type": "livechat:status", "ok": true } ontvangstbevestiging van deelname, en een momentopname van de sessiestatus (hieronder).

{
  "type": "livechat:status",
  "chatbotId": "YOUR_CHATBOT_ID",
  "sessionId": "SESSION_ID",
  "status": "open",
  "mode": "human",
  "userName": "John",
  "userEmail": "john@example.com",
  "userLanguage": "en"
}
VeldTypeBeschrijving
statusstringwaiting (nog geen agent), open (agent verbonden) of closed.
modestringbot of human.
userNamestring | nullNaam van de bezoeker, indien verzameld via Leads.
userEmailstring | nullE-mailadres van de bezoeker, indien verzameld.
userLanguagestring | nullGedetecteerde taal van de bezoeker.

livechat:message

Een nieuw (of backlog-)bericht.

{
  "type": "livechat:message",
  "id": 1024,
  "sessionId": "SESSION_ID",
  "sender": "admin",
  "content": "Hello! How can I help you today?",
  "country": "DE",
  "createdAt": "2025-01-15T10:30:00Z",
  "file": null,
  "audience": "admin",
  "historical": false
}
VeldTypeBeschrijving
idnumberBericht-ID (komt overeen met de REST-geschiedenis-id).
senderstringuser, admin of system.
contentstringBerichttekst. Voor admin-clients met vertaling ingeschakeld is dit al vertaald naar de taal van de admin.
countrystring | nullLandcode van de afzender, indien gedetecteerd.
createdAtstringISO 8601-tijdstempel.
fileobject | nullMetadata van het bijgevoegde bestand (uploadId, name, mimeType, size, url, isImage) wanneer het bericht een upload is.
audiencestring | null"admin" op het exemplaar van een bericht voor de admin. Het exemplaar voor de gebruiker laat dit weg.
historicalbooleantrue voor backlog-berichten die opnieuw worden afgespeeld bij deelname.

Systeemberichten: wanneer sender gelijk is aan system, is content een token dat je client moet lokaliseren en niet letterlijk moet weergeven: __agent_joined__, __livechat_ended__ of __livechat_timeout__.

livechat:typing

Typindicator van een andere deelnemer: { type, chatbotId, sessionId, sender, isTyping }.

livechat:presence

Online/offline-status van de bezoeker in een sessie: { type, chatbotId, sessionId, online } (boolean).

livechat:meta

Bijgewerkte sessiemetadata (huidige pagina, titel, referrer), alleen voor admins.

livechat:ended

De sessie is gesloten.

{
  "type": "livechat:ended",
  "sessionId": "SESSION_ID",
  "reason": "admin_closed"
}

reason is een van admin_closed, already_closed of timeout.

Events alleen voor admins

EventPayloadDoel
livechat:active_count{ chatbotId, count }Actieve sessies (wachtend + open).
livechat:waiting_count{ chatbotId, count }Wachtende sessies (badge voor onbeantwoorde chats).
livechat:new_request{ chatbotId, sessionId, status, mode, ... }Een nieuwe livechat heeft een agent nodig.
livechat:widget_sessions{ chatbotId, chatbotName, sessions }Huidige lijst van actieve widget-sessies.
livechat:notification{ chatbotId, sessionId, content, sender }Nieuw bericht terwijl de agent zich elders in het dashboard bevindt.

Automatische vertaling

De socket kan automatisch vertalen tussen de talen van de bezoeker en de agent:

  • Neem deel met translateEnabled: true en stel lang in op jouw taal.
  • Berichten van de andere partij komen al vertaald binnen in jouw lang. Elke partij behoudt de originele tekst; de vertaalde versie wordt aan de andere partij bezorgd.
  • Vertaling verloopt via Gemini, zodat een agent met een bezoeker in elke taal kan chatten zonder handmatig te vertalen.

Voorbeeld: Aangepaste livechat-client

const ws = new WebSocket('wss://webchatagent.com/api/livechat');

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'client:join',
    chatbotId: 'YOUR_CHATBOT_ID',
    sessionId: 'SESSION_ID',
    as: 'user',
    lang: 'en'
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  switch (data.type) {
    case 'livechat:status':
      // Join ack ({ ok: true }) or a session snapshot ({ status, mode, ... })
      if (data.ok) console.log('Joined');
      else console.log(`Status: ${data.status}, mode: ${data.mode}`);
      break;
    case 'livechat:message':
      if (data.sender === 'system') {
        // Localize tokens like __agent_joined__ / __livechat_ended__
        console.log('[system]', data.content);
      } else {
        console.log(`${data.sender}: ${data.content}`);
      }
      break;
    case 'livechat:typing':
      console.log(`${data.sender} is typing: ${data.isTyping}`);
      break;
    case 'livechat:ended':
      console.log(`Session ended: ${data.reason}`);
      ws.close();
      break;
  }
};

function sendMessage(text) {
  ws.send(JSON.stringify({
    type: 'client:message',
    chatbotId: 'YOUR_CHATBOT_ID',
    sessionId: 'SESSION_ID',
    sender: 'user',
    content: text,
    lang: 'en'
  }));
}

function sendTyping(isTyping) {
  ws.send(JSON.stringify({
    type: 'client:typing',
    chatbotId: 'YOUR_CHATBOT_ID',
    sessionId: 'SESSION_ID',
    sender: 'user',
    isTyping
  }));
}