Skip to Content

API de chat web

Conecta un formulario propio al widget de chat o crea una interfaz de chat propia con el SDK del widget, REST, indicador de escritura, SSE y actividad del visitante.

Última actualización el

El widget oficial se instala en la app: consulta Poner el chat en tu sitio web. Las opciones del snippet están en Ajustes del chat web. Esta página es para desarrolladores: el SDK del widget para un formulario propio y la capa REST para una interfaz de chat propia. Consulta OpenAPI, etiqueta inbox.

SDK del widget

Tras cargar el script del widget, window.TillorInbox está disponible. Con él pasas datos de contacto desde tu propio formulario (página de contacto, detalle de venta, solicitud de presupuesto). Todos los métodos esperan a que se haya cargado la configuración del widget.

MétodoDescripción
ready()Promise que se resuelve cuando el widget está cargado
getVisitor()Lee los datos de contacto guardados en localStorage y los campos del widget rellenados; síncrono, sin red
setVisitor({ name?, firstName?, lastName?, email?, phone?, message?, customFields? }, options?)Rellena los campos del chat sin enviar
open()Abre la ventana del chat
close()Cierra la ventana del chat
toggle()Abre o cierra la ventana del chat
send({ body, name?, firstName?, lastName?, email?, phone?, message?, customFields?, open?, silent?, markSubmitted?, metadata? })Envía un mensaje con datos de contacto

getVisitor() devuelve este objeto:

CampoDescripción
visitorIdID de este visitante en este navegador (localStorage)
nameNombre completo (un solo campo en el widget)
firstName / lastNameDerivados de name (primera palabra / resto)
email, phoneDatos de contacto
customFieldsCampos adicionales de los ajustes del widget
messageBorrador en el campo de mensaje
detailsSubmittedSi el formulario del visitante se considera rellenado

Usa getVisitor() para rellenar de antemano un formulario propio desde localStorage (mismo navegador, también tras recargar la página).

Opciones de setVisitor (segundo argumento):

OpciónPor defectoExplicación
openfalseAbrir la ventana del chat directamente
markSubmittedfalseOcultar el formulario del visitante si todos los campos obligatorios están rellenados
onlyEmptyfalseSobrescribir solo los campos vacíos
persistfalseGuardar los datos en localStorage (mismo navegador, también en una pestaña nueva)

Opciones de send:

OpciónPor defectoExplicación
openfalseAbrir la ventana del chat antes de enviar
silenttrue si open es falseSin sonido ni mensaje de error en el widget; usa la Promise para el éxito o el error
markSubmittedtrueLos datos de contacto no hace falta volver a introducirlos en el widget
metadata-Pistas opcionales para Tillie (no visibles en la ventana del chat); consulta metadata

Con open: false (por defecto) el botón del chat sigue cerrado. El mensaje sí llega a Tillor; tu propio formulario puede dar las gracias o mostrar un error. Con open: true se abre la ventana del chat y el visitante ve el comportamiento de envío normal (sonido, ticks, posibles errores del widget).

¿Quieres usar un botón propio en lugar del botón flotante del chat? Pon data-launcher="false" en el snippet y llama a TillorInbox.open().

metadata (formulario de reserva)

Usa metadata cuando tengas un formulario propio en el sitio web y Tillie deba enviar solo una confirmación, sin preguntas de seguimiento (por ejemplo porque la pestaña se cierra después).

ClaveTipoExplicación
forceHandoverbooleanMensaje de confirmación y traspaso a un compañero, sin preguntas de admisión. También ignora la pausa de la IA tras un mensaje del equipo (consulta ignoreAiPause)
ignoreAiPausebooleanTillie responde también cuando está en pausa en modo Automático tras un mensaje del equipo (30 minutos). Útil para un envío silencioso de formularios; combínalo con forceHandover o deja que Tillie haga la admisión normal
handoverIntent"reservation" | "caravan_rental" | "sale" | "other"Opcional: flujo para el traspaso (por defecto: se deduce automáticamente del mensaje)
sourcestringEtiqueta de integración opcional para tu equipo (minúsculas, cifras, -, _; máx. 64 caracteres)
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",
  },
});

Sustituir el formulario de contacto (envío silencioso)

Úsalo cuando quieras mantener el formulario de contacto existente, pero hacer que los mensajes pasen por Tillor sin abrir la ventana del 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>

No hace falta que pongas open ni silent: sin open: true la ventana permanece cerrada y Tillor trata la llamada como un envío silencioso.

Conectar el formulario de contacto (abrir el chat)

Pasar los campos y abrir la ventana del chat, para que el visitante vea la conversación:

<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>

O solo rellenar campos y abrir la ventana, sin enviar de inmediato:

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 página de venta con envío directo y apertura del 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,
});

Sincronizar en vivo mientras alguien escribe:

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,
  });
});

Llamar pronto (antes del script del widget)

Si llamas a un método antes de que se haya cargado el script, pon la llamada en la cola:

<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>

Interfaz de chat propia

Si creas una interfaz de chat propia en lugar del widget, usa la capa REST de abajo.

Autenticación: encabezado X-Tillor-Inbox-Widget-Key (valor de Configuración > Integraciones > Chat web).

Indicador de escritura

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: true cuando el visitante escribe; false cuando el campo está vacío o el visitante deja de escribir (el widget envía false tras unos 4 segundos sin entrada)
  • visitorName / visitorEmail / visitorPhone son opcionales
  • Usa el mismo visitorId que en POST …/inbox/website/messages y GET …/inbox/website/messages

Tiempo real (SSE)

GET /api/orgs/{orgId}/inbox/website/subscribe?visitorId=vis_…
X-Tillor-Inbox-Widget-Key: iwk_xxx
Accept: text/event-stream
EventoCuándo
inbox:website:message-createdNuevo mensaje del equipo o de la IA
inbox:website:message-updatedMensaje del equipo o de la IA modificado o eliminado
inbox:website:typing-changedCambia data.staffTyping o data.staffOutboundSenderType

La forma del payload es la misma que en el SSE de la organización (event, data, timestamp). Vuelve a conectarte tras una interrupción; no hay reanudación.

El widget oficial usa SSE como capa principal y vuelve a obtener GET …/messages cada 5 segundos como respaldo (cada 1 segundo con el panel abierto cuando SSE se interrumpe un momento). Así, las respuestas se marcan como entregadas mientras el visitante está en la página.

Actividad del visitante

POST /api/orgs/{orgId}/inbox/website/events
X-Tillor-Inbox-Widget-Key: iwk_xxx
Content-Type: application/json

event: chat_closed, tab_hidden o navigation (en la navegación también url). Tu equipo ve estos eventos como texto informativo en gris en la conversación, consulta Conversaciones por chat web.

Límites

POST …/inbox/website/messages y POST …/inbox/website/attachments/upload responden 429 cuando un visitante o una red envía demasiado. El cuerpo incluye data.reason = INBOX_WIDGET_RATE_LIMITED y data.retryAfterSeconds. Límites por organización:

RutaPor visitante (visitorId)Por red (dirección IP)
messages10 por minuto, 200 por día30 por minuto, 600 por día
attachments/upload10 por hora50 por hora

Espera retryAfterSeconds antes de volver a intentarlo y muestra un aviso al visitante en lugar de reintentar automáticamente.

Véase también

¿Te ha resultado útil esta página?

En esta página