Lelemon API
  • Guías
  • Referencia de la API
Crear un agenteConversar con un agenteConocimiento del agenteAcciones HTTPEscalamiento a un humanoMandar un mensaje a una conversaciónQue el agente escriba primeroAgendar en tu propia pantallaInventariar tus agentes para una auditoriaCatalogos y respuestas rapidas de un embudoDisponibilidad de una persona del equipoMetricas de las conversaciones
powered by Zudoku
Guías

Mandarle un mensaje a una persona desde tu sistema

Tu sistema escribe en una conversación que ya existe, por el mismo canal en que la persona habla con nosotros, sin que corra el agente. Sirve para una encuesta de satisfacción cuando el caso llega a su etapa de cierre, o para responderle desde tu mesa de soporte a alguien cuyo caso ya está escalado, sin copiar y pegar en la bandeja.

Base de la API de Lelemon: https://api.lelemon.cl

La idea de fondo: el mensaje sale con el texto que tú mandas, firmado con el nombre de tu credencial, y no pasa por el modelo. No gasta tokens, el agente no contesta por encima y la persona ve un mensaje de tu organización, no uno suyo.

Antes de empezar

Necesitas una credencial con el alcance conversations:send. Se emite en Integraciones API del dashboard, y al elegir ese alcance la pantalla te pide el nombre con el que firma. Ese nombre queda en cada mensaje que mande la credencial. Es lo que ve tu equipo en la bandeja y lo que llega en el aviso conversation.human_message, y en un widget embebido que lee el historial llega hasta la pantalla de la persona. Elige uno que diga qué es, como Encuesta de satisfacción o Mesa de soporte.

  • El nombre lo fija la credencial, no el pedido. Un campo de autor en el cuerpo se rechaza con 400 en vez de ignorarse, para que nadie crea que firmó con otro nombre. Así una integración no puede firmar con el nombre de una persona.
  • Una credencial con conversations:send sin nombre de autor no se puede emitir, y un nombre de autor sin ese alcance tampoco.
  • Rotar la credencial conserva el nombre.

El alcance va separado de agents:converse a propósito. Conversar escribe como si lo mandara la persona y hace correr al modelo; esto escribe como tu organización y no corre nada.

El pedido

Code
POST https://api.lelemon.cl/v1/external/conversations/{id}/send Authorization: Bearer <tu credencial> Content-Type: application/json { "message": "Hola Marcela, ¿cómo calificas la atención que recibiste? Responde de 1 a 5.", "externalRef": "encuesta-PROC-4821" }

{id} es el id de la conversación, el mismo conversation.dealId que viaja en los avisos y el que devuelven las otras rutas.

CampoTipoLímiteQué hace
messagetexto4.000 caracteresEl mensaje, tal cual sale. No puede venir vacío ni de solo espacios.
externalReftexto120 caracteresTu referencia para este envío. Es obligatoria: es lo que impide que un reintento mande el mensaje dos veces. Ver más abajo.

Manda sólo estos campos. Un campo de autor (senderName, authorName, author, senderId o userId) se rechaza con 400 y un mensaje que explica que el autor lo fija la credencial. Cualquier otro campo de más se ignora.

Code
{ "id": "b81d3f77-2c4a-4f19-9a86-31ee6c0b7d52", "messageId": "7f0c5e1a-39d2-4b8e-9f64-2d1a8c3b5e90", "alreadySent": false }

El mensaje queda guardado y encolado en el canal. Encolado no es entregado: el transporte lo despacha después, como con cualquier mensaje que escribe una persona de tu equipo.

Cuándo se puede mandar

La regla no es la etapa del caso sino quién lo está atendiendo. Si el agente está al mando de un caso abierto, tu mensaje llegaría por encima de lo que el agente está diciendo, y por eso se rechaza.

Estado de la conversaciónResultado
El agente la atiende y el caso está abierto409, código agent_in_control
Escalada, esperando que alguien la tomeSale
La tomó una persona del equipoSale
El caso está cerrado, aunque siga marcado como atendido por el agenteSale

El caso cerrado cubre la encuesta de cierre: un caso que llegó a su etapa final queda cerrado y nadie lo atiende, así que se le puede escribir.

Si te llega el 409, toma el control de la conversación desde la bandeja o cierra el caso, y vuelve a mandar con la misma externalRef: un rechazo no gasta la referencia.

Mandar un mensaje no cambia nada más. No mueve el caso de etapa, no cambia quién lo atiende y no reabre un caso cerrado.

La ventana de 24 horas de WhatsApp

Por WhatsApp, Meta sólo deja escribirle con texto libre dentro de las 24 horas siguientes al último mensaje de la persona. Pasado ese plazo sólo acepta plantillas aprobadas.

Esta ruta no envía plantillas. Si la ventana está cerrada, o si la persona nunca escribió, responde 422 con el código channel_window_closed y no manda nada:

Code
{ "statusCode": 422, "code": "channel_window_closed", "message": "Pasaron más de 24 horas desde el último mensaje de la persona y WhatsApp sólo deja escribirle con una plantilla aprobada, no con texto libre. Esta ruta todavía no envía plantillas: el mensaje no se mandó." }

Tómalo como un error de verdad, no como un aviso: el mensaje no salió. Para una encuesta de cierre, mándala dentro de las 24 horas del último mensaje de la persona.

La ventana es una regla del canal de WhatsApp, no de la ruta. Las conversaciones que entraron por la API o por el copiloto in-app no tienen ventana.

La referencia: reintentar sin duplicar

externalRef identifica un envío tuyo en una conversación. Dos llamadas a la misma conversación con la misma referencia mandan un solo mensaje:

  • La primera responde alreadySent: false y el messageId del mensaje guardado.
  • Las siguientes responden 200 con alreadySent: true y el mismo messageId, y no escriben nada.

Funciona también cuando los reintentos llegan a la vez. Si tu flujo se cae después de mandar y vuelve a intentar, o dos ejecuciones corren en paralelo, la persona recibe un solo mensaje.

  • La referencia vale por conversación: la misma referencia en otra conversación es otro envío.
  • Un reintento responde igual aunque el caso haya cambiado de manos desde el primer envío: lo ya enviado no se vuelve a evaluar.
  • Una referencia distinta es un mensaje distinto, aunque el texto sea el mismo.
  • Arma la referencia con el hecho que origina el mensaje, como encuesta-<id del ticket>, y no con un valor que cambie en cada intento, como la hora.

Errores

Llegan con el cuerpo habitual (statusCode, message, path). Los de esta ruta traen además code.

CódigoQué pasóQué hacer
400Falta message o externalRef, vienen vacíos, muy largos o no son texto, el cuerpo trae un campo de autor, o el {id} no es un UUID.Arreglar el pedido. Reintentar igual no sirve.
401Falta la credencial o no es válida.Revisar la cabecera y la clave.
403A la credencial le falta conversations:send, o la tiene pero no tiene nombre de autor.Emitir una credencial con el alcance y su nombre.
404La conversación no existe o es de otra organización.Verificar el id.
409 agent_in_controlEl agente atiende un caso abierto.Tomar el control o cerrar el caso, y reintentar con la misma externalRef.
422 channel_window_closedPasaron más de 24 horas desde el último mensaje de la persona y sólo se puede con plantilla.No reintentar igual: no va a cambiar solo.
422 no_outbound_channelLa conversación no tiene por dónde escribirle a la persona.Escribirle por otro medio.
429Pasaste un techo por minuto: 3.000 pedidos por credencial o 200 por dirección IP, compartidos por toda la API externa.Esperar y reintentar. Es seguro. Si mandas muchos mensajes seguidos, espácialos: la ruta no tiene envío en lote.
500Error nuestro.Reintentar con espera y la misma externalRef: es seguro.

Ejemplo con curl

TerminalCode
curl -X POST "https://api.lelemon.cl/v1/external/conversations/b81d3f77-2c4a-4f19-9a86-31ee6c0b7d52/send" \ -H "Authorization: Bearer lel_a1b2c3d4e5f6_<...>" \ -H "Content-Type: application/json" \ -d '{ "message": "Hola Marcela, ¿cómo calificas la atención que recibiste? Responde de 1 a 5.", "externalRef": "encuesta-PROC-4821" }'

Cómo ver lo que se mandó

  • GET /v1/external/conversations/{id}/messages, con conversations:read, devuelve el hilo. El mensaje sale con rol human.
  • Si tienes configurado el aviso conversation.human_message, te llega también cuando manda tu propia credencial. El aviso no trae el texto: trae dónde encontrarlo y el nombre del autor.

Bajar los archivos de una conversación

Para traer a tu sistema lo que la persona mandó por el chat y lo que quedó en la ficha del caso:

Code
GET https://api.lelemon.cl/v1/external/conversations/{id}/adjuntos Authorization: Bearer <tu credencial>

Pide conversations:read, el mismo alcance que leer la conversación. Acepta limit y offset, como las demás listas.

Code
{ "data": [ { "id": "3b1f6c0e-5d0a-4a52-9a43-0c7c0f6a2e11", "nombre": "Contrato firmado.pdf", "mime": "application/pdf", "tamano": 48213, "fecha": "2026-10-21T14:05:00.000Z", "origen": "ficha", "subidoPor": "cliente", "url": "https://...", "venceEn": "2026-10-21T14:15:00.000Z" } ], "limit": 50, "offset": 0, "hasMore": false }
CampoQué es
idEl id del archivo en la ficha, o el id del mensaje que lo trajo si vino por el chat.
nombreEl nombre original del archivo. Una imagen, un audio o un video del chat no guardan el nombre que tenían en el teléfono: salen con el nombre con que se guardaron.
mimeEl tipo del archivo.
tamanoBytes. null en lo que vino por el chat, que no guarda el peso.
fechaCuándo llegó al chat o se adjuntó a la ficha.
origenchat o ficha.
subidoPorcliente o equipo. Todo lo de chat es del cliente; en ficha, lo que entró por WhatsApp es del cliente y lo que cargó alguien del equipo en la ficha es del equipo.
urlDirección firmada para descargar, sin credencial.
venceEnHasta cuándo sirve la url.

Qué trae cada origen:

  • chat: las imágenes, los audios y los videos que mandó la persona. No trae los archivos que tu equipo manda por el chat.
  • ficha: todo lo que está en la ficha del caso: los documentos que la persona mandó por el chat, que quedan guardados ahí con su nombre original, y los archivos que subió tu equipo. Un documento no sale dos veces. Para quedarte sólo con lo del cliente, filtra por subidoPor: "cliente".

El más nuevo viene primero, mezclando los dos orígenes.

La url vive 10 minutos. Descárgala apenas pidas la lista; si venció, pide la lista de nuevo. Baja con su nombre en Content-Disposition. Sólo los pdf, las imágenes, el audio y el video se abren en línea; cualquier otro tipo, y en particular un html o un svg, baja siempre como archivo.

Una imagen que el filtro de seguridad bloqueó no se ofrece. Tampoco sale lo que se borró.

Un 404 significa que la conversación no existe o es de otra organización. El resto de los errores son los habituales de la API: 401, 403 si falta conversations:read, 429.

Lo que esta ruta no hace

  • No envía plantillas de WhatsApp. Fuera de las 24 horas no hay forma de usarla.
  • No escribe sobre un caso que el agente está atendiendo. No hay una opción para forzarlo.
  • No manda archivos. Sólo texto.
  • No elige el autor por pedido. Lo fija la credencial.
  • No crea conversaciones. Para empezar una con un agente, ver lelemon-api-agentes.md, y para que el agente escriba primero, lelemon-api-triggers.md.

Notas internas: avisarle al equipo sin escribirle a la persona

Una nota interna es un mensaje que queda en el chat de la conversación y que ve solo tu equipo, con el rótulo "Nota interna", su autor y su hora. Sirve para dejar constancia desde tu sistema, por ejemplo que el ticket no se pudo crear al escalar un caso.

Una nota nunca sale a la persona por ningún canal, no la lee el agente ni entra a sus resúmenes, y no viaja en los avisos hacia tu sistema. Tampoco mueve la espera ni la última actividad del caso, no reinicia el reloj del cierre por inactividad ni cuenta para el tope de mensajes de la conversación, y se puede dejar con el agente al mando, escalada o con el caso cerrado.

Necesitas una credencial con el alcance conversations:annotate, aparte de conversations:send: una integración que solo avisa de sus fallos no necesita poder escribirle a la persona. La nota se firma con el nombre de autor de la credencial si lo tiene y, si no, con el nombre de la credencial.

Code
POST https://api.lelemon.cl/v1/external/conversations/{id}/notas Authorization: Bearer <tu credencial> Content-Type: application/json { "texto": "No se pudo crear el ticket en Jira: respondió 503.", "externalRef": "fallo-escalamiento-PROC-4821" }
CampoTipoLímiteQué hace
textotexto4.000 caracteresLa nota. No puede venir vacía ni de solo espacios.
externalReftexto, opcional120 caracteresTu referencia para esta nota. Con la misma referencia en la misma conversación, un reintento no deja la nota dos veces.

Un campo de autor (senderName, authorName, author, senderId o userId) se rechaza con 400: el autor lo fija la credencial.

Code
{ "id": "b81d3f77-2c4a-4f19-9a86-31ee6c0b7d52", "messageId": "7f0c5e1a-39d2-4b8e-9f64-2d1a8c3b5e90", "createdAt": "2026-10-21T15:30:00.000Z", "alreadyCreated": false }

Un reintento con la misma externalRef responde 200 con alreadyCreated: true y el mismo messageId. Los errores son los de la ruta de enviar, salvo 409 y 422, que acá no existen. Un 404 es una conversación que no existe o es de otra organización, y un 403 es una credencial sin conversations:annotate.

Leer las notas

GET /v1/external/conversations/{id}/messages no las devuelve, para no cambiar el hilo a quien ya lo lee. Con ?incluirNotas=true las trae en su lugar, con role: "internal_note" y el nombre del autor en author:

Code
{ "role": "internal_note", "content": "No se pudo crear el ticket en Jira: respondió 503.", "createdAt": "2026-10-21T15:30:00.000Z", "author": "n8n de la mesa de soporte" }

incluirNotas=true lo puede usar cualquier credencial con conversations:read: no hay un alcance aparte para leer notas. Dale ese alcance solo a sistemas que pueden ver lo que anota tu equipo.

Si muestras ese hilo a la persona, descarta los mensajes con rol internal_note.

Desde el dashboard

En el chat, el compositor tiene el modo "Nota interna". Lo puede usar quien puede responder conversaciones, sin tomar el control, y la nota queda firmada con su nombre.

Escalamiento a un humanoQue el agente escriba primero
On this page
  • Antes de empezar
  • El pedido
  • Cuándo se puede mandar
  • La ventana de 24 horas de WhatsApp
  • La referencia: reintentar sin duplicar
  • Errores
  • Ejemplo con curl
  • Cómo ver lo que se mandó
  • Bajar los archivos de una conversación
  • Lo que esta ruta no hace
  • Notas internas: avisarle al equipo sin escribirle a la persona
    • Leer las notas
    • Desde el dashboard
JSON
JSON
JSON
JSON
JSON