Website chat API
Koppel een eigen formulier aan de chatwidget of bouw een eigen chat-UI met de widget-SDK, REST, typen, SSE en bezoekersactiviteit.
Laatst bijgewerkt op
Het officiële widget installeer je in de app: zie De chat op je website zetten. Opties van het snippet staan op Instellingen van Website chat. Deze pagina is voor ontwikkelaars: de widget-SDK voor een eigen formulier en de REST-laag voor een eigen chat-UI. Zie OpenAPI, tag inbox.
Widget-SDK
Na het laden van het widget-script staat window.TillorInbox klaar. Daarmee geef je contactgegevens door vanaf je eigen formulier (contactpagina, verkoopdetail, offerte-aanvraag). Alle methodes wachten tot de widget-config geladen is.
| Methode | Beschrijving |
|---|---|
ready() | Promise die klaar is zodra het widget geladen is |
getVisitor() | Leest opgeslagen contactgegevens uit localStorage en ingevulde widgetvelden; synchroon, geen netwerk |
setVisitor({ name?, firstName?, lastName?, email?, phone?, message?, customFields? }, options?) | Vult chatvelden in zonder te versturen |
open() | Opent het chatvenster |
close() | Sluit het chatvenster |
toggle() | Opent of sluit het chatvenster |
send({ body, name?, firstName?, lastName?, email?, phone?, message?, customFields?, open?, silent?, markSubmitted?, metadata? }) | Verstuurt een bericht met contactgegevens |
getVisitor() geeft dit object terug:
| Veld | Beschrijving |
|---|---|
visitorId | Id van deze bezoeker in deze browser (localStorage) |
name | Volledige naam (één veld in het widget) |
firstName / lastName | Afgeleid uit name (eerste woord / rest) |
email, phone | Contactgegevens |
customFields | Extra velden uit de widget-instellingen |
message | Concept in het berichtveld |
detailsSubmitted | Of het bezoekersformulier als ingevuld geldt |
Gebruik getVisitor() om een eigen formulier vooraf in te vullen vanuit localStorage (zelfde browser, ook na een pagina-verversing).
Opties voor setVisitor (tweede argument):
| Optie | Standaard | Uitleg |
|---|---|---|
open | false | Chatvenster direct openen |
markSubmitted | false | Verberg het bezoekersformulier als alle verplichte velden ingevuld zijn |
onlyEmpty | false | Alleen lege velden overschrijven |
persist | false | Gegevens in localStorage bewaren (zelfde browser, ook na een nieuw tabblad) |
Opties voor send:
| Optie | Standaard | Uitleg |
|---|---|---|
open | false | Chatvenster openen vóór het versturen |
silent | true als open false is | Geen geluid, geen foutmelding in het widget; gebruik de Promise voor succes of fout |
markSubmitted | true | Contactgegevens hoeven daarna niet opnieuw in het widget |
metadata | - | Optionele hints voor Tillie (niet zichtbaar in het chatvenster); zie metadata |
Met open: false (standaard) blijft de chatknop dicht. Het bericht gaat wel naar Tillor; je eigen formulier kan bedanken of een fout tonen. Met open: true opent het chatvenster en ziet de bezoeker het normale verzendgedrag (geluid, vinkjes, eventuele widget-fouten).
Wil je zelf een knop gebruiken in plaats van de zwevende chatknop? Zet data-launcher="false" op het snippet en roep TillorInbox.open() aan.
metadata (boekingsformulier)
Gebruik metadata wanneer je een eigen formulier op de website hebt en Tillie alleen een bevestiging moet sturen, zonder vervolgvragen (bijvoorbeeld omdat het tabblad daarna sluit).
| Sleutel | Type | Uitleg |
|---|---|---|
forceHandover | boolean | Bevestigingsbericht en overdracht aan een collega, zonder intake-vragen. Negeert ook de AI-pauze na een teambericht (zie ignoreAiPause) |
ignoreAiPause | boolean | Tillie antwoordt ook wanneer ze in Automatisch-modus gepauzeerd is na een teambericht (30 minuten). Handig voor stille formulierverzending; combineer met forceHandover of laat Tillie normaal intake doen |
handoverIntent | "reservation" | "caravan_rental" | "sale" | "other" | Optioneel: flow voor de overdracht (standaard: automatisch afleiden uit het bericht) |
source | string | Optioneel integratielabel voor je team (kleine letters, cijfers, -, _; max. 64 tekens) |
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",
},
});Contactformulier vervangen (stille verzending)
Gebruik dit wanneer je het bestaande contactformulier wilt houden, maar berichten via Tillor wilt laten lopen zonder het chatvenster te openen.
<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>open en silent hoef je niet te zetten: zonder open: true blijft het venster dicht en behandelt Tillor de aanroep als stille verzending.
Contactformulier koppelen (chat openen)
Velden doorgeven en het chatvenster openen, zodat de bezoeker het gesprek ziet:
<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>Of alleen velden invullen en het venster openen, zonder meteen te versturen:
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 },
);Een verkooppagina met direct versturen en chat openen:
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,
});Live synchroniseren terwijl iemand typt:
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,
});
});Vroeg aanroepen (vóór het widget-script)
Roep je een methode aan voordat het script geladen is, zet de aanroep dan in de wachtrij:
<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>Eigen chat-UI
Bouw je een eigen chat-UI in plaats van de widget, dan gebruik je de REST-laag hieronder.
Authenticatie: header X-Tillor-Inbox-Widget-Key (waarde uit Instellingen > Integraties > Website chat).
Typen
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: truewanneer de bezoeker typt;falsewanneer het veld leeg is of de bezoeker stopt (het widget stuurtfalsena ongeveer 4 seconden zonder input)visitorName/visitorEmail/visitorPhonezijn optioneel- Gebruik hetzelfde
visitorIdals bijPOST …/inbox/website/messagesenGET …/inbox/website/messages
Realtime (SSE)
GET /api/orgs/{orgId}/inbox/website/subscribe?visitorId=vis_…
X-Tillor-Inbox-Widget-Key: iwk_xxx
Accept: text/event-stream| Event | Wanneer |
|---|---|
inbox:website:message-created | Nieuw team- of AI-bericht |
inbox:website:message-updated | Team- of AI-bericht gewijzigd of verwijderd |
inbox:website:typing-changed | data.staffTyping of data.staffOutboundSenderType verandert |
Payload-vorm is hetzelfde als org-SSE (event, data, timestamp). Herverbind na verbreking; er is geen resumption.
Het officiële widget gebruikt SSE als primaire laag en haalt GET …/messages elke 5 seconden opnieuw op als fallback (elke 1 seconde met open paneel wanneer SSE even wegvalt). Daardoor worden antwoorden als afgeleverd gemarkeerd zolang de bezoeker op de pagina is.
Bezoekersactiviteit
POST /api/orgs/{orgId}/inbox/website/events
X-Tillor-Inbox-Widget-Key: iwk_xxx
Content-Type: application/jsonevent: chat_closed, tab_hidden of navigation (bij navigatie ook url). Je team ziet deze gebeurtenissen als grijze infotekst in het gesprek, zie Gesprekken via Website chat.