API della chat del sito web
Collega un modulo tuo al widget di chat o crea una tua interfaccia di chat con l'SDK del widget, REST, digitazione, SSE e attività dei visitatori.
Ultimo aggiornamento il
Il widget ufficiale lo installi nell'app: vedi Mettere la chat sul tuo sito web. Le opzioni dello snippet sono in Impostazioni della Chat sul sito web. Questa pagina è per gli sviluppatori: l'SDK del widget per un modulo tuo e il livello REST per una interfaccia di chat tua. Vedi OpenAPI, tag inbox.
SDK del widget
Dopo il caricamento dello script del widget, window.TillorInbox è pronto. Con esso passi i dati di contatto dal tuo modulo (pagina contatti, dettaglio di una vendita, richiesta di preventivo). Tutti i metodi aspettano che la configurazione del widget sia caricata.
| Metodo | Descrizione |
|---|---|
ready() | Promise che si risolve non appena il widget è caricato |
getVisitor() | Legge i dati di contatto salvati da localStorage e i campi del widget compilati; sincrono, senza rete |
setVisitor({ name?, firstName?, lastName?, email?, phone?, message?, customFields? }, options?) | Compila i campi della chat senza inviare |
open() | Apre la finestra della chat |
close() | Chiude la finestra della chat |
toggle() | Apre o chiude la finestra della chat |
send({ body, name?, firstName?, lastName?, email?, phone?, message?, customFields?, open?, silent?, markSubmitted?, metadata? }) | Invia un messaggio con i dati di contatto |
getVisitor() restituisce questo oggetto:
| Campo | Descrizione |
|---|---|
visitorId | ID di questo visitatore in questo browser (localStorage) |
name | Nome completo (un solo campo nel widget) |
firstName / lastName | Ricavati da name (prima parola / resto) |
email, phone | Dati di contatto |
customFields | Campi aggiuntivi dalle impostazioni del widget |
message | Bozza nel campo del messaggio |
detailsSubmitted | Se il modulo del visitatore risulta compilato |
Usa getVisitor() per precompilare un modulo tuo da localStorage (stesso browser, anche dopo un aggiornamento della pagina).
Opzioni per setVisitor (secondo argomento):
| Opzione | Predefinito | Spiegazione |
|---|---|---|
open | false | Apre subito la finestra della chat |
markSubmitted | false | Nasconde il modulo del visitatore se tutti i campi obbligatori sono compilati |
onlyEmpty | false | Sovrascrive solo i campi vuoti |
persist | false | Conserva i dati in localStorage (stesso browser, anche dopo una nuova scheda) |
Opzioni per send:
| Opzione | Predefinito | Spiegazione |
|---|---|---|
open | false | Apre la finestra della chat prima dell'invio |
silent | true se open è false | Nessun suono, nessun messaggio di errore nel widget; usa la Promise per successo o errore |
markSubmitted | true | Dopo l'invio i dati di contatto non devono essere reinseriti nel widget |
metadata | - | Suggerimenti facoltativi per Tillie (non visibili nella finestra della chat); vedi metadata |
Con open: false (predefinito) il pulsante della chat resta chiuso. Il messaggio arriva comunque a Tillor; il tuo modulo può ringraziare o mostrare un errore. Con open: true si apre la finestra della chat e il visitatore vede il normale comportamento di invio (suono, spunte, eventuali errori del widget).
Vuoi usare un pulsante tuo invece del pulsante di chat flottante? Imposta data-launcher="false" sullo snippet e chiama TillorInbox.open().
metadata (modulo di prenotazione)
Usa metadata quando hai un modulo tuo sul sito web e Tillie deve inviare solo una conferma, senza domande successive (ad esempio perché la scheda si chiude subito dopo).
| Chiave | Tipo | Spiegazione |
|---|---|---|
forceHandover | boolean | Messaggio di conferma e passaggio a un collega, senza domande di raccolta dati. Ignora anche la pausa dell'AI dopo un messaggio del team (vedi ignoreAiPause) |
ignoreAiPause | boolean | Tillie risponde anche quando è in pausa in modalità Automatico dopo un messaggio del team (30 minuti). Utile per l'invio silenzioso di moduli; combinalo con forceHandover oppure lascia che Tillie faccia normalmente la raccolta dati |
handoverIntent | "reservation" | "caravan_rental" | "sale" | "other" | Facoltativo: flusso per il passaggio (predefinito: dedotto automaticamente dal messaggio) |
source | string | Etichetta di integrazione facoltativa per il tuo team (lettere minuscole, cifre, -, _; max. 64 caratteri) |
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",
},
});Sostituire il modulo di contatto (invio silenzioso)
Usa questo quando vuoi mantenere il modulo di contatto esistente, ma far passare i messaggi da Tillor senza aprire la finestra della 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>Non devi impostare open e silent: senza open: true la finestra resta chiusa e Tillor tratta la chiamata come invio silenzioso.
Collegare il modulo di contatto (aprire la chat)
Passare i campi e aprire la finestra della chat, così il visitatore vede la conversazione:
<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>Oppure compilare solo i campi e aprire la finestra, senza inviare subito:
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 },
);Una pagina di vendita con invio immediato e apertura della 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,
});Sincronizzare in tempo reale mentre qualcuno digita:
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,
});
});Chiamare in anticipo (prima dello script del widget)
Se chiami un metodo prima che lo script sia caricato, metti la chiamata in coda:
<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>Interfaccia di chat propria
Se crei un'interfaccia di chat tua invece del widget, usa il livello REST qui sotto.
Autenticazione: header X-Tillor-Inbox-Widget-Key (valore da Impostazioni > Integrazioni > Chat sul sito web).
Digitazione
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: truequando il visitatore digita;falsequando il campo è vuoto o il visitatore smette (il widget inviafalsedopo circa 4 secondi senza input)visitorName/visitorEmail/visitorPhonesono facoltativi- Usa lo stesso
visitorIddiPOST …/inbox/website/messageseGET …/inbox/website/messages
Tempo reale (SSE)
GET /api/orgs/{orgId}/inbox/website/subscribe?visitorId=vis_…
X-Tillor-Inbox-Widget-Key: iwk_xxx
Accept: text/event-stream| Evento | Quando |
|---|---|
inbox:website:message-created | Nuovo messaggio del team o dell'AI |
inbox:website:message-updated | Messaggio del team o dell'AI modificato o eliminato |
inbox:website:typing-changed | data.staffTyping o data.staffOutboundSenderType cambia |
La forma del payload è la stessa dell'SSE dell'organizzazione (event, data, timestamp). Riconnettiti dopo un'interruzione; non c'è ripresa.
Il widget ufficiale usa SSE come livello primario e richiede di nuovo GET …/messages ogni 5 secondi come fallback (ogni 1 secondo con il pannello aperto quando SSE si interrompe per un momento). In questo modo le risposte vengono contrassegnate come consegnate finché il visitatore è sulla pagina.
Attività dei visitatori
POST /api/orgs/{orgId}/inbox/website/events
X-Tillor-Inbox-Widget-Key: iwk_xxx
Content-Type: application/jsonevent: chat_closed, tab_hidden o navigation (con la navigazione anche url). Il tuo team vede questi eventi come testo informativo grigio nella conversazione, vedi Conversazioni tramite Chat sul sito web.
Limiti
POST …/inbox/website/messages e POST …/inbox/website/attachments/upload rispondono 429 quando un visitatore o una rete invia troppo. Il corpo contiene data.reason = INBOX_WIDGET_RATE_LIMITED e data.retryAfterSeconds. Limiti per organizzazione:
| Percorso | Per visitatore (visitorId) | Per rete (indirizzo IP) |
|---|---|---|
messages | 10 al minuto, 200 al giorno | 30 al minuto, 600 al giorno |
attachments/upload | 10 all'ora | 50 all'ora |
Aspetta retryAfterSeconds prima di riprovare e mostra un avviso al visitatore invece di riprovare automaticamente.