Widget & SDK
Côté visiteur, l’intégration se fait en deux temps : créer une session visiteur (qui rend un jeton signé de courte durée), puis ouvrir un WebSocket authentifié par ce jeton. Les SDK font cet enchaînement pour vous.
Le cycle de vie d’une session
Section intitulée « Le cycle de vie d’une session »- Le widget appelle
GET /create/visitor-session(ouGET /fetch/widget-configd’abord, pour rendre le lanceur sans encore créer de session). - Le relais renvoie un jeton visiteur (JWT, ~1 h) lié à
(tenant_id, widget_public_key, origin), plus la config publique du widget. - Le widget ouvre
WSS /ws/widget?token=<jwt>et reçoit une tramewelcome. - À l’expiration, le widget appelle
POST /refresh/visitor-token(enBearerl’ancien jeton, même expiré) pour reprendre la même conversation — la session Redis vit beaucoup plus longtemps (~30 jours) que le JWT.
Créer une session visiteur
Section intitulée « Créer une session visiteur »POST /create/visitor-session est public mais CORS-gated : le relais
valide origin contre les allowed_origins du tenant (sinon 403).
curl $BASE_URL/api/v1/create/visitor-session \ -X POST \ -H "Content-Type: application/json" \ -d '{ "tenant_id": "019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "widget_public_key": "pk_...", "origin": "https://app.acme.com", "locale": "fr" }'{ "status_code": 201, "data": { "session_id": "vs_...", "visitor_token": "<jwt>", "expires_at": "2026-06-21T11:00:00Z", "widget_config": { "tenant_name": "Demo Boutique", "is_online": true, "...": "..." } }, "message": "Visitor session created."}Champs du corps : tenant_id, widget_public_key, origin (requis),
locale (défaut fr), metadata (contexte libre), routing_key (file
de destination, ex. un store id) et mode (bot par défaut, ou
human pour aller droit à la file opérateur).
Le WebSocket /ws/widget
Section intitulée « Le WebSocket /ws/widget »Le WebSocket visiteur n’est pas un endpoint HTTP classique : le jeton
passe en paramètre de requête (?token=<jwt>), car un navigateur ne
peut pas poser d’en-tête personnalisé sur la poignée de main d’un upgrade
WebSocket.
WSS $BASE_URL/api/v1/ws/widget?token=<visitor_jwt>Codes de fermeture applicatifs à gérer côté client :
4401— jeton visiteur invalide (re-créez/rafraîchissez une session).4404— session expirée côté serveur (re-créez une session).
Les trames sont du JSON discriminé par un champ type. Quelques exemples
issus du protocole :
| Sens | type | Rôle |
|---|---|---|
| visiteur → serveur | msg | Envoyer un message (client_msg_id + content) |
| visiteur → serveur | typing | Indicateur de frappe (state: start|stop) |
| visiteur → serveur | ping | Battement de cœur (le serveur répond pong) |
| serveur → visiteur | welcome | Première trame après connexion (session + config) |
| serveur → visiteur | ack | Accusé de réception d’un message (écho client_msg_id) |
| serveur → visiteur | msg | Message du bot, d’un agent ou du système |
| serveur → visiteur | typing | Frappe du bot ou de l’agent |
Vous n’avez normalement pas à parler ce protocole à la main : les SDK l’enveloppent.
Les SDK web
Section intitulée « Les SDK web »Bibliothèque Angular à composants standalone, service à base de signaux, compatible SSR. Cible Angular 17+.
npm install @bloonio/chat-angular @bloonio/chat-client-coreImportez la feuille de style une fois dans styles.css :
@import "@bloonio/chat-angular/styles.css";Déclarez le fournisseur :
import { provideBloonioChat } from '@bloonio/chat-angular';
export const appConfig = { providers: [ provideBloonioChat({ tenantId: '019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f', publicKey: 'pk_...', baseUrl: '$BASE_URL', locale: 'fr', // Optionnel — lier les sessions anonymes à vos utilisateurs. // Votre backend calcule HMAC-SHA256(tenant_secret, user_id). // visitorTokenProvider: () => ... // renvoie "userId:signature" }), ],};Trois modes de rendu, qui partagent tous le même BloonioChatService :
| Mode | Composant | Quand |
|---|---|---|
| Flottant | <bloonio-chat-launcher /> | Bulle dans le coin qui s’ouvre au clic. |
| Panneau ancré | <bloonio-chat-panel mode="docked" /> | Chat permanent dans une colonne dédiée. |
| Fil sans chrome | <bloonio-chat-thread /> | Juste les messages + la saisie, à intégrer. |
Accès programmatique via le service :
import { inject } from '@angular/core';import { BloonioChatService } from '@bloonio/chat-angular';
const chat = inject(BloonioChatService);chat.unreadCount; // Signal<number>chat.botTyping; // Signal<boolean>chat.openPanel();chat.sendMessage('Où est ma commande ?');Le bootstrap (fetchWidgetConfig) est différé via afterNextRender, donc
le rendu serveur ne fait aucun appel réseau ; les composants se connectent
à l’hydratation.
Cœur TypeScript agnostique du framework, zéro dépendance runtime — c’est la couche transport que les autres SDK enveloppent. Utilisez-le directement pour un widget maison ou un framework non couvert.
npm install @bloonio/chat-client-coreimport { ChatClient, WSClient } from '@bloonio/chat-client-core';
const client = new ChatClient({ baseUrl: '$BASE_URL' });
// 1. Bootstrap (config seule, pas de session)const cfg = await client.fetchWidgetConfig({ tenantId: '019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f', widgetPublicKey: 'pk_...', origin: window.location.origin,});
// 2. Créer une session visiteur (JWT signé)const sess = await client.createVisitorSession({ tenantId: cfg.tenant_id, widgetPublicKey: 'pk_...', origin: window.location.origin,});
// 3. Ouvrir le WebSocketconst ws = new WSClient( { baseUrl: '$BASE_URL', visitorToken: sess.visitor_token }, { onWelcome: (f) => console.log('welcome', f), onMessage: (f) => console.log('msg', f), onTyping: (f) => console.log('typing', f), onError: (f) => console.error('proto error', f), },);ws.connect();
// 4. Envoyer un messagews.send({ type: 'msg', client_msg_id: 'c1', content: 'Où est ma commande ?' });WSClient gère le ping/pong et la reconnexion à back-off exponentiel
(0,5 s → 30 s). ChatClient enveloppe /fetch/widget-config,
/create/visitor-session et /identify/visitor.
Identifier un visiteur
Section intitulée « Identifier un visiteur »Pour lier une session anonyme à l’un de vos utilisateurs connectés,
appelez POST /identify/visitor en Bearer le jeton visiteur, avec une
user_signature calculée côté serveur :
hex(hmac_sha256(tenant_secret, user_id)). La signature serveur empêche
un script malveillant de forger des identités.
Étapes suivantes
Section intitulée « Étapes suivantes »- La surface REST exacte. Voir la Référence API.
- Recevoir les événements sur votre backend. Voir Webhooks.
- Brancher des opérateurs humains. Voir Opérateurs.