Darle acciones a un agente de Lelemon desde otra aplicación
Documento para el equipo que va a escribir la integración. Describe cómo registrar una acción HTTP —una llamada a un sistema de ustedes que el agente puede hacer en medio de una conversación— y cómo concedérsela o quitársela a un agente. Alcanza para implementar el lado de ustedes sin preguntarnos nada.
Base de la API de Lelemon: https://api.lelemon.cl
Qué resuelve esto
Un agente contesta con lo que sabe. Con una acción, además hace: abre un ticket en el sistema de ustedes, consulta el estado de un pedido, agenda algo en su calendario. La acción es una URL de ustedes, un método, y un esquema de los parámetros que el agente va a completar con lo que entendió de la conversación.
Son dos recursos distintos, y conviene tenerlos separados desde el principio:
- La acción es de la organización. Se registra una vez, con su URL y su credencial.
- La concesión es por agente. Una acción registrada no la usa nadie hasta que se le concede a un agente concreto, de a una.
Todo va con la credencial de organización en la cabecera Authorization:
Code
Alcances: actions:read para ver, actions:write para registrar, dar de baja, conceder y quitar. actions:write es el permiso más delicado de la API —una acción HTTP manda datos de contactos de ustedes al sistema que la acción apunte— así que se lo dan sólo a integraciones que ya administran.
Una credencial con actions:write sólo registra acciones hacia los sitios que tiene permitidos. La lista la escribe una persona con rol de administrador en Integraciones, API, al emitir la credencial o después, y la credencial no la puede cambiar. Un sitio es esquema, host y puerto: https://n8n.ejemplo.cl no permite http://n8n.ejemplo.cl ni https://otro.n8n.ejemplo.cl. Así, si la credencial se filtra, quien la tenga no puede crear una acción que mande los datos a un servidor suyo.
1. Si van a dejar registrada la autorización: el texto
Code
No pide alcance: alcanza con una credencial viva.
Una acción manda datos de las conversaciones —nombre, RUT, teléfono, lo que la persona cuente— al sistema que ustedes indiquen. La Ley 21.719 (art. 15 bis) pide que el responsable de esos datos nos haya autorizado a entregarlos: quién, para qué, hacia dónde. Esa autorización puede constar en el contrato marco que tienen con nosotros, y por eso registrar la acción no la exige. Si prefieren dejarla registrada acción por acción —con versión del texto, país de destino y finalidad, consultable después—, la mandan en el mismo cuerpo, y para eso está este endpoint: lo que aceptan tiene versión, y la versión viaja en el cuerpo. Si no van a mandarla, salten al paso 2.
La respuesta
Code
version es lo que va en autorizacionVersion si registran la autorización. Guárdenla en la configuración de su integración, no en el código: cuando el texto cambie, el registro empieza a contestar 400 nombrando la versión que mandaron y la vigente, y la corrección es volver a leer este endpoint y actualizar ese valor.
fueraDeChile es un segundo texto, aparte. Si el sistema al que apunta la acción está alojado fuera de Chile —o no saben dónde—, los datos salen del país y eso es una transferencia internacional (art. 27): hay que confirmarla por separado, y queda registrada por separado.
2. Registrar una acción
Code
Alcance: actions:write.
El cuerpo
| Campo | Tipo | Límite | Obligatorio | Qué hace |
|---|---|---|---|---|
slug | texto | 64 | sí | Identificador de la acción. Es con lo que se le concede a un agente, y es la llave para reintentar sin duplicar: mandar el mismo slug dos veces actualiza la misma acción con lo que manden, y conserva lo que no manden (las cabeceras, si no vienen, siguen). |
name | texto | 100 | sí | Cómo se llama. |
description | texto | 2000 | sí | Lo que lee el agente para decidir cuándo usarla. Sin esto no la usa nunca. Escríbanla para el agente, no para una persona: "Consulta el estado de un pedido por su número. Usar cuando el cliente pregunte dónde está su compra." |
url | texto | 2000 | sí | A dónde llama. http o https, pública y alcanzable: una dirección privada o que no resuelve da 400. No vuelve en ninguna respuesta: de la dirección sólo devolvemos el origen. |
method | texto | — | sí | GET, POST, PUT, PATCH o DELETE. |
headers | objeto | — | no | Nombre de cabecera a valor. Acá viaja la credencial del sistema de ustedes. Se cifra antes de guardarse y no vuelve nunca, ni siquiera enmascarada. |
parameters | objeto | — | no | JSON Schema de los parámetros que el agente completa. Los nombres de estos parámetros son lo que queda registrado como "qué datos salen". |
timeout | entero | ms | no | Cuánto esperamos la respuesta de ustedes. |
paraClientes | booleano | — | no | A qué agentes se les puede conceder. Sin mandarlo, a cualquiera: a quién se la dan se decide al concederla (paso 4). true: sólo a los que atienden desconocidos por WhatsApp. false: sólo al asistente interno de ustedes. Tiene que ser un booleano de verdad: "false" entre comillas da 400, no lo convertimos. |
purpose | texto | 500 | no* | Para qué es. Parte de la autorización: la ley pide que el encargo declare su finalidad. |
destinationCountry | texto | — | no* | Dónde está alojado el sistema: chile, fuera_de_chile o desconocido. Lo declaran ustedes; no lo detectamos, porque con un CDN adelante el DNS miente. desconocido cuenta como fuera. |
autorizacionVersion | texto | — | no* | La version que devolvió el paso 1. |
confirmaSalidaDelPais | booleano | — | con la autorización, si el destino no es chile | La segunda confirmación. Sin ella, una autorización con destino fuera de Chile da 400. |
* La autorización es un bloque: o no mandan nada de purpose, destinationCountry y autorizacionVersion —y la acción se registra igual, sin autorización registrada— o mandan los tres. Dos de tres es 400 que dice cuál falta: una autorización a medias, con la finalidad en blanco o el país sin decir, sería peor que ninguna.
La respuesta
201 con la acción, sin la URL:
Code
audience es a quién se le puede conceder: null es cualquiera (lo que queda sin paraClientes), external sólo los que atienden clientes, internal sólo el asistente interno.
origin y no url, y headerNames y no headers, a propósito: en un webhook de n8n el path es el token, y actions:read es el alcance que se le da a un auditor.
Ejemplo con curl
Con la autorización registrada. Sin ella, saquen las tres últimas líneas del cuerpo y el VERSION.
Code
Códigos de estado
| Código | Cuándo |
|---|---|
201 | Registrada (o actualizada, si el slug ya existía). |
400 | Falta un campo de la acción, la autorización vino a medias, la autorizacionVersion no es la vigente, el destino sale de Chile sin confirmaSalidaDelPais, paraClientes no es un booleano, o la URL no se puede usar (privada, no resuelve, no es http/https). El mensaje dice cuál. |
401 | Credencial ausente, revocada o inválida. |
403 | A la credencial le falta actions:write, o la URL apunta a un sitio que la credencial no tiene permitido. Reescribir por slug una acción que apunta a un sitio no permitido también da 403, aunque no cambien la URL. El mensaje dice qué sitio falta. |
429 | Pasaron un techo por minuto: 3.000 pedidos por credencial o 200 por dirección IP. Esperen lo que diga Retry-After. |
Por qué reintentar no duplica
Mandar el mismo slug es la misma acción, esté activa o dada de baja. Si está activa, se actualiza con lo que venga en el cuerpo y se conserva lo que no venga; si cambian el sistema al que apunta (otro origen), la autorización anterior queda revocada —era para lo que había antes— y la nueva se registra si vino. Si está dada de baja, revive: dar de baja no borra, porque el registro de qué acción se ejecutó contra qué sistema tiene que seguir siendo legible después, así que el slug queda ocupado por una fila que el listado no muestra. Un guion de aprovisionamiento que corre dos veces deja una sola acción, con lo último que mandó.
3. Ver las acciones
Code
Alcance: actions:read. Devuelve { "data": [ ... ] } con las acciones HTTP que registraron ustedes, con la misma forma que la respuesta del registro. No incluye las acciones nuestras ni las de un servidor MCP: para saber qué puede tener un agente concreto está el paso siguiente.
Code
Alcance: actions:read. El catálogo completo que ese agente puede tener, con enabled diciendo cuáles tiene concedidas hoy:
Code
source es una etiqueta para mostrar, no un código: Tus sistemas para lo que registraron ustedes, Lelemon para las acciones que traemos nosotros, y el nombre del servidor MCP o del conector cuando viene de ahí. No programen contra ese texto.
Sale el catálogo entero y no sólo lo concedido, porque para prender una hay que saber su slug, y un cliente que sólo viera lo suyo concluiría que el resto no se puede conceder. Sin la dirección ni cabeceras. Con actions:read, cada entrada trae destinationOrigin: el origen al que sale la acción, sea HTTP, de un servidor MCP o de un conector, y null si es una herramienta nativa de Lelemon. Está explicado en la guía para inventariar agentes.
4. Conceder y quitar
Code
Alcance: actions:write. Los dos devuelven 204 sin cuerpo. Los dos son idempotentes: conceder lo que ya estaba, o quitar lo que no estaba, no es un error.
Se concede de a una, nunca mandando la lista entera. Si tuvieran que mandar el conjunto completo, para agregar una tendrían que leer las que hay, sumar la suya y mandar todo — y entre el leer y el mandar, lo que alguien concedió desde el panel desaparece sin error y sin rastro. Dos concesiones simultáneas por dos procesos distintos quedan las dos.
Códigos de estado
| Código | Cuándo |
|---|---|
204 | Concedida / quitada. |
400 | Sólo en PUT: esa acción no existe para su organización, o no alcanza a este agente. Quitar no valida: si una acción dejó de existir hay que poder sacársela igual. |
404 | El agente no existe, no es de su organización, o es el asistente interno. |
Por qué el asistente interno da 404
El asistente interno de ustedes trae herramientas que leen contactos con su teléfono, tratos y líneas de cartola. Con actions:write se podría registrar una acción a una URL propia y concedérsela: no haría falta ni hablarle, el dueño le escribe mañana y los datos salen solos. Por eso la API no lo toca: ni le concede, ni le quita, ni lista lo que tiene. Y el 404 es el mismo que el de un agente que no existe, para no confirmar cuál de los identificadores probados es el interno.
5. Dar de baja una acción
Code
Alcance: actions:write. 204. Deja de estar disponible y se retira de todos los agentes que la tenían concedida, en el momento. El slug queda ocupado: volver a registrarlo revive esta misma acción (ver el punto 2). 404 si no tienen una acción con ese slug.
6. El cuerpo de los errores
Igual que en el resto de la API: statusCode, code, message y, cuando es un 400 de validación, errors con el campo que falló y la forma de lo que llegó, nunca su valor.
Códigos de error
Decidan por code, no por el texto del message: el texto puede cambiar y el code no. Los que importan al registrar una acción:
code | Status | Cuándo pasa | Qué hacer |
|---|---|---|---|
validation_failed | 400 | El cuerpo no cumple lo que pide la ruta. | Corregir el pedido. |
action_destination_blocked | 400 | La dirección no es una URL pública http o https. | Usar una URL pública. |
action_origin_not_allowed | 403 | La credencial no puede crear acciones hacia ese sitio. | Que un administrador agregue el sitio a la credencial en Integraciones, API. |
api_key_invalid | 401 | Falta la credencial, está mal escrita, fue revocada o venció. | Revisar la clave o pedir una nueva. |
scope_missing | 403 | La credencial no tiene el permiso que pide la ruta. | Pedir que le agreguen ese permiso. |
rate_limited | 429 | Pasaron el límite de pedidos. | Esperar lo que diga Retry-After. |
Si el error no tiene un código propio, code toma uno según el statusCode (not_found para 404, conflict para 409, internal_error para 500, y así). La tabla completa está en la guía de agentes, sección 7.
El 400 por versión vieja del texto es el único que conviene manejar por programa, porque va a pasar el día que el texto cambie y le va a pasar a todas las integraciones a la vez:
Code
Lo razonable es que su integración, ante ese mensaje, avise a una persona: aceptar un texto legal nuevo automáticamente es justamente lo que el texto pide que no pase.
7. Lo que todavía no hacemos
- Probarla. El botón de "probar" del panel no tiene equivalente por API.