Live Chat API — Integration with your server (1.0)

Download OpenAPI specification:Download

INTRODUCTION

Integration of the Live Chat with your own server: every time a message occurs in a conversation we send a POST request (JSON) to the URL you configure, and whatever your server replies is applied to the conversation: answering the visitor, offering buttons or closing the chat.



This way your own business logic can respond in real time: look up an order status in your ERP and answer it, identify the visitor against your CRM, launch a survey with buttons and store the answer, or log the whole conversation in your ticketing system.



You do not have to reply at all. If your server does not answer, answers too late or returns something that is not JSON, the conversation carries on as usual and your agent handles it as always. The integration never blocks the chat.



Please note: event names and JSON field names are in Spanish because they are the literal wire format. Use them exactly as shown (mensaje-recibido, not message-received).

ACTIVATION

In your panel: Chat → Websites, edit the site and fill in the «Reports to your server» section:
- URL (https): must be https and a public host. For security, private or reserved IPs are rejected (127.0.0.1, 10.x, 192.168.x, ::1…) and redirects are not followed.
- Authentication: the value you type here is sent verbatim in the Authorization header of every request (for example Bearer my_secret_token). Check it on your server and reject anything that does not match.



The setting belongs to the account, not to the site: the first active site that has a URL is used, and it applies to every conversation of the account, whether it comes from the web widget or from WhatsApp, SMS or email.

WHAT THE REQUEST LOOKS LIKE

Always a POST with Content-Type: application/json, a JSON body and a 5 second timeout. The Evento field tells you what happened; ignore any event you do not recognise (new ones will be added keeping this format).

EventWhen it is sentIs your reply applied?
mensaje-recibidoINBOUND message: written by the visitor (Emisor = 0).Yes.
mensaje-enviadoOUTBOUND message: written by your agent, the AI assistant or the system. Check Emisor to tell which.No. You are notified so you can log it, but nothing is applied: otherwise your own replies would trigger another reply and it would loop.
pulsacion-chipThe visitor presses one of the message chips, the [label|value] ones. They do not navigate anywhere: they send a value back into the conversation.Yes, always.
pulsacion-botonThe visitor opens a link button (an <a class="boton-chat">) among those marked for tracking.Yes.
enlace-pulsadoThe visitor opens a link inside the text among those marked for tracking.Yes.
encuesta-cierreThe visitor rates the service with a smiley of the closing survey.Yes.
conversacion-cerradaThe conversation has been closed, by an agent or by your own reply.No. Replying to a closure would reopen the conversation in practice, and if your script always answers the same, it would loop.


A note on the three click events, which is the part that usually needs explaining: a chip carries no URL and its value comes back into the conversation as a visitor reply; a button and a link do carry a URL and you are told when somebody opens them. Keeping them apart lets you measure what works without mixing two different things in one counter.

YOUR SERVER'S REPLY

Reply 2xx with a JSON object. Every field is optional; if you return an empty body nothing happens:

FieldWhat it does
responderText posted in the conversation as a reply to the visitor. Supports basic HTML and buttons (see below). Maximum 4,000 characters.
refYour own reference (max. 64 characters). It is stored with the message and comes back in every click event when the visitor presses a chip, a button or a link of that message. This is what lets you match the click with the request that produced it.
htmlForces how the text is handled: true treats it as HTML even if no tag is recognised, false leaves it as plain text even if it has tags. If you omit it, it is decided automatically (see HTML).
cerrartrue closes the conversation.
seguirtrue to be told when the visitor opens the links of this message. See Link tracking.
estadisticaName under which the clicks of this message are grouped so they can be counted (max. 40 characters). Implies seguir.

CLICK STATISTICS

Clicks are not stored unless you name them, with "estadistica": "name" or with data-estadistica on the link. Without a name you are told about the click and nothing is kept: piling up your visitors' browsing when nobody asked for it adds nothing and involves personal data.



Use the same name across several messages to group a whole campaign.

BUTTONS

Buttons are written inside the text of responder, using the format [label|value]:


- The label is what the visitor sees (usually an emoji, text works too).
- The value is what we send back to you when it is pressed.
- Up to 10 buttons per message; the markers are removed from the text that is displayed.
- The visitor can only press once per message; afterwards the buttons are disabled.



Appearance: if no label contains letters or digits (that is, they are emojis or symbols), the buttons are drawn round and large, like the survey smileys. As soon as one label contains text they are all drawn as normal buttons. It is automatic and does not change the value that is returned.


      Emojis -> round:   "[😍|5][🙂|4][😐|3][🙁|2][😞|1]"
      Text   -> normal:  "[Yes|yes][No|no]"
      Mixed  -> normal:  "[😍|5][I would rather not answer|x]"

There are no buttons outside the web chat. On WhatsApp, SMS or email only the text is sent, already without the markers.

HTML

The text of responder supports basic HTML and is always sanitised against a whitelist before being published:


- Allowed tags: b strong i em u s br p ul ol li a code small blockquote. Any other tag is dropped but its text is kept.
- Removed entirely, contents included: script, style, iframe, img, form and the like, plus every attribute (style=, onclick=…).
- Links only accept http, https, mailto and tel, and come out with target="_blank" and rel="noopener noreferrer nofollow".
- If you leave a tag unclosed, it is closed for you: malformed HTML does not break the message.



You do not need to ask for HTML: if the text contains one of the allowed tags it is sanitised; if not, it is treated as plain text as always. It works this way so that an ordinary message such as "5 < 10" is not parsed as a tag and does not lose that fragment. With html you can force either behaviour.



On WhatsApp, SMS or email the plain text version is sent (<br> becomes line breaks and links become text: url).

FULL EXAMPLE: SURVEY WITH A REFERENCE

1) The visitor writes their last message («thanks, it is sorted now») and your server receives mensaje-recibido. It replies with the survey and its reference:


Careful: the survey has to be launched from a mensaje-recibido. On mensaje-enviado your reply is not applied (see the events table), so it cannot be used to react to the agent closing the chat; for that there is the close with survey button in the panel, which sends it on its own.


      {
        "responder": "Please rate how we did<br/>[😍|5][🙂|4][😐|3][🙁|2][😞|1]",
        "ref": "12345AB"
      }

2) The visitor presses the first smiley and your server receives the encuesta-cierre event with your reference, the value pressed and the visitor's details:


      {
        "Evento": "encuesta",  "idConversacion": 88,  "idMensaje": 1420,
        "Canal": "web",        "Valor": "5",         "Nota": 5,
        "Ref": "12345AB",      "idAgente": 7,        "Fecha": "2026-08-01 12:40:11",
        "Visitante": {
          "idVisitante": 12,   "Nombre": "Ana",  "Email": "ana@customer.com",  "Telefono": "",
          "IP": "10.0.20.100", "UserAgent": "Mozilla/5.0...",
          "Url": "https://yourshop.com/cart", "Idioma": "es", "Zona": "Europe/Madrid",
          "Pais": "Spain", "Ciudad": "Madrid", "Operadora": "Movistar",
          "Vars": { "order": "8812" },
          "idSitio": 3, "Canal": "web", "RefCanal": ""
        }
      }

3) Your server can still answer something to that click and close:


      { "responder": "Thanks for your feedback!", "cerrar": true }

EXAMPLE: RECEIVER IN PHP


      $expected = 'Bearer my_secret_token';
      if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== $expected) { http_response_code(401); exit; }

      $d = json_decode(file_get_contents('php://input'), true);
      header('Content-Type: application/json');

      // Button press: matched against the reference we sent earlier
      if (($d['Evento'] ?? '') === 'encuesta') {
        storeRating($d['Ref'], $d['Valor'], $d['Visitante']['Email'] ?? '');
        echo json_encode(['responder' => 'Thanks, we will take it into account.', 'cerrar' => true]);
        exit;
      }

      // Message from the VISITOR. Outbound ones are not answered.
      if (($d['Evento'] ?? '') === 'mensaje-recibido') {
        if (stripos($d['Cuerpo'], 'order') !== false) {
          echo json_encode([
            'responder' => '<b>Order 881</b> has shipped. Anything else? [Yes|yes][No|no]',
            'ref'       => 'ORD-881'
          ]);
          exit;
        }
      }

      echo '{}';   // do nothing: the conversation carries on with the agent

basicAuth

HTTP Basic authentication. Use your API User as the username and your API Token as the password (you will find them in your panel, under Your Data → Configure Account). The resulting header is Authorization: Basic base64(APIUser:APIToken). Most HTTP libraries build it automatically (curl -u, requests auth=, Ruby's basic_auth, etc.) without needing to encode the base64 by hand.

Security Scheme Type: HTTP
HTTP Authorization Scheme: basic

Request your server will receive

https://{YourServer}/script-receiver-on-your-server

POST REQUEST (JSON) THAT WE SEND TO YOUR URL ON EVERY CHAT MESSAGE.

It carries the Authorization header with the value you configured in the panel: check it and return 401 if it does not match. Reply 2xx with JSON (see «Your server's reply» in the Introduction) within 5 seconds. If you do not reply, the conversation carries on as usual and your agent handles it.



Fields marked as belonging to the click events (Valor, Nota, Ref, Visitante…) do not arrive in the message events, and the other way round.

Authorizations:
basicAuth
Request Body schema:

Parámetros recibidos en su script en petición POST con la configuración especificada en su panel de usuario/configuración API.

Evento
required
string

What happened:
mensaje-recibido written by the visitor
mensaje-enviado written by your agent, the AI assistant or the system
pulsacion-chip a [label|value] chip was pressed
pulsacion-boton a link button was opened
enlace-pulsado a link in the text was opened
encuesta-cierre the service was rated with a smiley
conversacion-cerrada the conversation was closed

Ignore any event you do not recognise: new ones will be added keeping this format.

idConversacion
required
integer

Conversation identifier. It is stable for the whole conversation: use it to group the messages in your system.

Canal
required
string

Channel the conversation started from: web (widget on your site), whatsapp, sms, rcs or email. Buttons and HTML are only visible on web.

idMensaje
required
integer

Message identifier. In the click events it is the id of the message that contained the buttons, not of the click.

Inicio
integer

Message events only. 1 if this is the FIRST message of the conversation, 0 otherwise. It tells you whether to open a new record in your system or append to an existing one, without keeping count yourself.

Motivo
string

conversacion-cerrada only. Who closed it: agente (a person from the panel) or webhook (your own reply with cerrar).

ConEncuesta
integer

conversacion-cerrada only. 1 if the visitor was asked to rate the service on closing. In that case an encuesta-cierre event is still to come — or will never come if they do not answer: do not treat the record as fully closed until then.

Mensajes
integer

conversacion-cerrada only. Total number of messages in the conversation.

Duracion
integer

conversacion-cerrada only. Seconds between the first message and the closure.

Destino
string

pulsacion-boton and enlace-pulsado only. The URL the visitor opened.

Estadistica
string

pulsacion-boton and enlace-pulsado only. The name you grouped that link under, if you gave it one.

Emisor
integer

Only in the message events. Who wrote it: 0 visitor, 1 agent, 2 system, 3 AI assistant. The direction is already given by Evento (0 is always mensaje-recibido); Emisor is there to tell, within the outbound ones, whether a person or the AI assistant answered.

Cuerpo
string

Only in the message events. Text of the message.

Valor
string

Only in the click events. The value of the button pressed, that is the right-hand side of your [label|value].

Nota
integer

Only in the click events. The same Valor cast to a number, or null if it was not one. Handy when the values are scores from 1 to 5.

Texto
string

Only in the click events. The label of the button pressed, exactly as the visitor saw it (the emoji or the text).

Ref
string

Only in the click events. The reference you sent in the ref field when you delivered the buttons. Empty string if you did not send one.

Visitante
object

Only in the click events. Details of the person chatting:
idVisitante - stable identifier of the visitor within your account.
Nombre, Email, Telefono - whatever they left in the chat (empty if they did not).
IP, UserAgent, Url - IP, browser and page they are writing from.
Idioma, Zona - browser language and time zone.
Pais, Ciudad, Operadora - geolocation by IP (may come back empty).
Vars - object with the custom fields your site asked for in the chat form.
idSitio, Canal, RefCanal - originating site, channel and identifier of the party on that channel (phone or email; empty on web).
FechaAlta, UltimaActividad - first time we saw them and last activity.

idAgente
integer

Only in the click events. Agent the conversation was assigned to (0 if the account holder handled it or it was unassigned). Useful to break the ratings down per agent in your own reports.

Fecha
required
string

Date and time of the event, in YYYY-MM-DD HH:MM:SS format and mainland Spanish time.

Request samples

Content type
{
  • "Evento": "mensaje-recibido",
  • "idConversacion": "88",
  • "Canal": "web",
  • "idMensaje": "1420",
  • "Inicio": "1",
  • "Motivo": "agente",
  • "ConEncuesta": "0",
  • "Mensajes": "14",
  • "Duracion": "842",
  • "Estadistica": "summer-offer",
  • "Emisor": "0",
  • "Cuerpo": "Hello, I would like to know where my order is",
  • "Valor": "5",
  • "Nota": "5",
  • "Texto": "😍",
  • "Ref": "12345AB",
  • "Visitante": "{ \"idVisitante\": 12, \"Nombre\": \"Ana\", \"Email\": \"ana@customer.com\", \"IP\": \"10.0.20.100\", \"Pais\": \"Spain\", \"Vars\": { \"order\": \"8812\" } }",
  • "idAgente": "7",
  • "Fecha": "2026-08-01 12:40:11"
}