API du chat du site web
Reliez votre propre formulaire au widget de chat ou créez votre propre interface de chat avec le SDK du widget, REST, la saisie, le SSE et l'activité des visiteurs.
Dernière mise à jour le
Vous installez le widget officiel dans l'application : voir Mettre le chat sur votre site. Les options du snippet se trouvent sur Paramètres du chat du site. Cette page s'adresse aux développeurs : le SDK du widget pour votre propre formulaire et la couche REST pour une interface de chat personnalisée. Voir OpenAPI, tag inbox.
SDK du widget
Après le chargement du script du widget, window.TillorInbox est disponible. Il vous permet de transmettre des coordonnées depuis votre propre formulaire (page de contact, détail d'une vente, demande de devis). Toutes les méthodes attendent que la configuration du widget soit chargée.
| Méthode | Description |
|---|---|
ready() | Promise résolue dès que le widget est chargé |
getVisitor() | Lit les coordonnées enregistrées dans localStorage et les champs du widget remplis ; synchrone, sans réseau |
setVisitor({ name?, firstName?, lastName?, email?, phone?, message?, customFields? }, options?) | Remplit les champs du chat sans envoyer |
open() | Ouvre la fenêtre de chat |
close() | Ferme la fenêtre de chat |
toggle() | Ouvre ou ferme la fenêtre de chat |
send({ body, name?, firstName?, lastName?, email?, phone?, message?, customFields?, open?, silent?, markSubmitted?, metadata? }) | Envoie un message avec les coordonnées |
getVisitor() renvoie cet objet :
| Champ | Description |
|---|---|
visitorId | ID de ce visiteur dans ce navigateur (localStorage) |
name | Nom complet (un seul champ dans le widget) |
firstName / lastName | Déduits de name (premier mot / reste) |
email, phone | Coordonnées |
customFields | Champs supplémentaires issus des paramètres du widget |
message | Brouillon dans le champ de message |
detailsSubmitted | Indique si le formulaire du visiteur est considéré comme rempli |
Utilisez getVisitor() pour préremplir votre propre formulaire depuis localStorage (même navigateur, aussi après un rafraîchissement de la page).
Options pour setVisitor (deuxième argument) :
| Option | Par défaut | Explication |
|---|---|---|
open | false | Ouvrir directement la fenêtre de chat |
markSubmitted | false | Masquer le formulaire du visiteur si tous les champs obligatoires sont remplis |
onlyEmpty | false | N'écraser que les champs vides |
persist | false | Conserver les données dans localStorage (même navigateur, aussi après un nouvel onglet) |
Options pour send :
| Option | Par défaut | Explication |
|---|---|---|
open | false | Ouvrir la fenêtre de chat avant l'envoi |
silent | true si open vaut false | Pas de son, pas de message d'erreur dans le widget ; utilisez la Promise pour le succès ou l'échec |
markSubmitted | true | Les coordonnées n'ont plus besoin d'être saisies à nouveau dans le widget |
metadata | - | Indications facultatives pour Tillie (non visibles dans la fenêtre de chat) ; voir metadata |
Avec open: false (par défaut), le bouton de chat reste fermé. Le message part bien vers Tillor ; votre propre formulaire peut remercier ou afficher une erreur. Avec open: true, la fenêtre de chat s'ouvre et le visiteur voit le comportement d'envoi habituel (son, coches, éventuelles erreurs du widget).
Vous voulez utiliser votre propre bouton à la place du bouton de chat flottant ? Mettez data-launcher="false" sur le snippet et appelez TillorInbox.open().
metadata (formulaire de réservation)
Utilisez metadata lorsque vous avez votre propre formulaire sur le site et que Tillie doit uniquement envoyer une confirmation, sans questions de suivi (par exemple parce que l'onglet se ferme ensuite).
| Clé | Type | Explication |
|---|---|---|
forceHandover | boolean | Message de confirmation et transfert à un collègue, sans questions d'admission. Ignore aussi la pause de l'IA après un message de l'équipe (voir ignoreAiPause) |
ignoreAiPause | boolean | Tillie répond aussi lorsqu'elle est en pause en mode Automatique après un message de l'équipe (30 minutes). Pratique pour un envoi de formulaire silencieux ; combinez avec forceHandover ou laissez Tillie mener l'admission normalement |
handoverIntent | "reservation" | "caravan_rental" | "sale" | "other" | Facultatif : flux pour le transfert (par défaut : déduit automatiquement du message) |
source | string | Libellé d'intégration facultatif pour votre équipe (minuscules, chiffres, -, _ ; 64 caractères max.) |
await TillorInbox.send({
name: "Jan Janssens",
email: "jan@voorbeeld.be",
phone: "+32 3 779 81 64",
body: structuredBookingMessage,
silent: true,
metadata: {
forceHandover: true,
handoverIntent: "reservation",
source: "website_booking_form",
},
});Remplacer le formulaire de contact (envoi silencieux)
Utilisez ceci si vous voulez garder le formulaire de contact existant, mais faire passer les messages par Tillor sans ouvrir la fenêtre de chat.
<form id="site-contact-form">
<input name="name" type="text" required />
<input name="email" type="email" required />
<input name="phone" type="tel" />
<textarea name="message" required></textarea>
<button type="submit">Verstuur</button>
<p id="contact-status" hidden></p>
</form>
<script>
document.getElementById("site-contact-form").addEventListener("submit", async (event) => {
event.preventDefault();
const form = event.currentTarget;
const status = document.getElementById("contact-status");
const data = new FormData(form);
try {
await TillorInbox.send({
name: String(data.get("name") ?? ""),
email: String(data.get("email") ?? ""),
phone: String(data.get("phone") ?? ""),
body: String(data.get("message") ?? ""),
});
status.textContent = "Bedankt, we nemen snel contact op.";
status.hidden = false;
form.reset();
} catch (error) {
status.textContent = error instanceof Error ? error.message : "Versturen mislukt.";
status.hidden = false;
}
});
</script>Vous n'avez pas besoin de définir open ni silent : sans open: true, la fenêtre reste fermée et Tillor traite l'appel comme un envoi silencieux.
Relier le formulaire de contact (ouvrir le chat)
Transmettre les champs et ouvrir la fenêtre de chat, pour que le visiteur voie la conversation :
<form id="site-contact-form">
<input name="name" type="text" required />
<input name="email" type="email" required />
<input name="phone" type="tel" />
<textarea name="message" required></textarea>
<button type="submit">Verstuur</button>
</form>
<script>
document.getElementById("site-contact-form").addEventListener("submit", (event) => {
event.preventDefault();
const form = event.currentTarget;
const data = new FormData(form);
void TillorInbox.send({
name: String(data.get("name") ?? ""),
email: String(data.get("email") ?? ""),
phone: String(data.get("phone") ?? ""),
body: String(data.get("message") ?? ""),
open: true,
});
});
</script>Ou seulement remplir les champs et ouvrir la fenêtre, sans envoyer tout de suite :
void TillorInbox.setVisitor(
{
name: "Jan Janssens",
email: "jan@voorbeeld.be",
phone: "+32 3 779 81 64",
message: "Ik heb een vraag over de stacaravan te koop.",
},
{ markSubmitted: true, open: true },
);Une page de vente avec envoi direct et ouverture du chat :
void TillorInbox.send({
name: "Jan Janssens",
email: "jan@voorbeeld.be",
phone: "+32 3 779 81 64",
body: "Ik heb interesse in deze stacaravan.",
open: true,
});Synchroniser en direct pendant que quelqu'un tape :
const form = document.getElementById("site-contact-form");
form.addEventListener("input", () => {
void TillorInbox.setVisitor({
name: form.name.value,
email: form.email.value,
phone: form.phone.value,
message: form.message.value,
});
});Appeler tôt (avant le script du widget)
Si vous appelez une méthode avant que le script soit chargé, mettez l'appel en file d'attente :
<script>
window.TillorInbox = window.TillorInbox || { q: [] };
window.TillorInbox.q.push([
"setVisitor",
{ name: "Jan", email: "jan@voorbeeld.be" },
{ open: true },
]);
</script>
<script src="https://tillor.eu/inbox-widget.js" data-org-id="org_abc123" data-widget-key="iwk_xxx" async defer></script>Interface de chat personnalisée
Si vous créez votre propre interface de chat à la place du widget, vous utilisez la couche REST ci-dessous.
Authentification : en-tête X-Tillor-Inbox-Widget-Key (valeur issue de Paramètres > Intégrations > Chat du site web).
Saisie
POST /api/orgs/{orgId}/inbox/website/typing
X-Tillor-Inbox-Widget-Key: iwk_xxx
Content-Type: application/json
{
"visitorId": "vis_…",
"active": true,
"visitorName": "Jan",
"visitorEmail": "jan@voorbeeld.nl",
"visitorPhone": "+32470123456"
}active: truelorsque le visiteur tape ;falselorsque le champ est vide ou que le visiteur arrête (le widget envoiefalseaprès environ 4 secondes sans saisie)visitorName/visitorEmail/visitorPhonesont facultatifs- Utilisez le même
visitorIdque pourPOST …/inbox/website/messagesetGET …/inbox/website/messages
Temps réel (SSE)
GET /api/orgs/{orgId}/inbox/website/subscribe?visitorId=vis_…
X-Tillor-Inbox-Widget-Key: iwk_xxx
Accept: text/event-stream| Événement | Quand |
|---|---|
inbox:website:message-created | Nouveau message de l'équipe ou de l'IA |
inbox:website:message-updated | Message de l'équipe ou de l'IA modifié ou supprimé |
inbox:website:typing-changed | data.staffTyping ou data.staffOutboundSenderType change |
Le format du payload est le même que pour le SSE de l'organisation (event, data, timestamp). Reconnectez-vous après une coupure ; il n'y a pas de reprise.
Le widget officiel utilise le SSE comme couche principale et récupère GET …/messages toutes les 5 secondes en solution de repli (toutes les secondes avec le panneau ouvert lorsque le SSE se coupe un instant). Ainsi, les réponses sont marquées comme remises tant que le visiteur est sur la page.
Activité des visiteurs
POST /api/orgs/{orgId}/inbox/website/events
X-Tillor-Inbox-Widget-Key: iwk_xxx
Content-Type: application/jsonevent : chat_closed, tab_hidden ou navigation (pour la navigation, aussi url). Votre équipe voit ces événements sous forme de texte d'information grisé dans la conversation, voir Conversations via le chat du site.
Limites
POST …/inbox/website/messages et POST …/inbox/website/attachments/upload répondent 429 quand un visiteur ou un réseau envoie trop. Le corps contient data.reason = INBOX_WIDGET_RATE_LIMITED et data.retryAfterSeconds. Limites par organisation :
| Route | Par visiteur (visitorId) | Par réseau (adresse IP) |
|---|---|---|
messages | 10 par minute, 200 par jour | 30 par minute, 600 par jour |
attachments/upload | 10 par heure | 50 par heure |
Attends retryAfterSeconds avant de réessayer, et affiche un message au visiteur au lieu de réessayer automatiquement.