Sendly MCP
Envía correos transaccionales, ejecuta campañas y gestiona contactos, listas y segmentos en Sendly. Servidor remoto con inicio de sesión OAuth.
Servidor MCP alojado
npx add-mcp 'https://app.sendly.now/api/mcp'Se instala en Claude Code, Codex, Cursor y más
Documentación
Servidor MCP (/guides/mcp)
Sendly ejecuta un servidor remoto de Model Context Protocol. Conecta un cliente de IA compatible con MCP, elige lo que puede hacer, y el agente puede trabajar directamente en tu cuenta de Sendly: responder qué dominios están verificados, ordenar tus contactos, diagnosticar por qué un mensaje no llegó, crear y pausar tus automatizaciones, redactar la próxima campaña y, si tú lo autorizas, enviarla.
Los permisos que no se pueden deshacer (enviar correo, revocar una clave de API, eliminar una dirección de tu lista de supresión) **nunca se otorgan por defecto**. Aparecen sin marcar en la pantalla de consentimiento, cada uno con una frase sencilla que indica la consecuencia, y tú mismo los marcas. Todo lo demás es un permiso que puedes retirar más tarde sin desconectarte.Endpoint [#endpoint]
https://app.sendly.now/api/mcp
El transporte es HTTP Streamable. La autorización es OAuth 2.1 con PKCE, o una clave secreta de Sendly.
Sendly aparece en el registro oficial de MCP como *now.sendly/sendly**. El listado es
solo metadatos: el endpoint anterior, el transporte que utiliza y el encabezado
opcional Authorization — porque Sendly es un servidor remoto: no hay nada que
instalar ni ningún paquete que descargar. Un cliente que encuentre Sendly a través
del registro se conecta exactamente a la URL que de otro modo pegarías manualmente.
Conectar [#connect]
Claude Code [#claude-code]
La primera llamada a una herramienta abre un navegador en Sendly, donde inicias sesión y eliges los permisos. Después de eso, la conexión persiste.
¿Configurando otro agente (Codex, Cursor, Windsurf, OpenCode o VS Code/Copilot)? Consulta Onboard your agent para ver el comando exacto por cliente, o pega el agent-setup prompt en el propio agente y deja que ejecute la configuración.
Claude (web y escritorio) [#claude-web-and-desktop]
Añade Sendly como conector personalizado en la configuración de Claude, usando la URL del endpoint anterior. Los conectores personalizados están disponibles en los planes de pago de Claude; la política de tu espacio de trabajo de Claude decide si los miembros pueden añadirlos.
Cualquier otro cliente MCP [#any-other-mcp-client]
Sendly funciona con cualquier cliente que hable HTTP Streamable y admita el flujo de código de autorización OAuth con PKCE. Dale al cliente la URL del endpoint: no hay ninguna aplicación que pre-registrar. El cliente descubre todo lo que necesita y se registra automáticamente:
| Documento de descubrimiento | URL |
|---|---|
| Metadatos de recurso protegido (RFC 9728) | https://app.sendly.now/.well-known/oauth-protected-resource |
| Metadatos del servidor de autorización (RFC 8414) | https://app.sendly.now/.well-known/oauth-authorization-server |
El emisor es https://app.sendly.now/api/auth. El registro dinámico de clientes está
abierto, por lo que un cliente que nunca haya hablado con Sendly puede registrarse
e iniciar el flujo sin supervisión. También se sirven alias insertados en la ruta
de ambos documentos, para que los clientes que deriven la URL de metadatos de
cualquier manera puedan encontrarla.
Conectar con una clave de API [#connecting-with-an-api-key]
Coloca la clave en el encabezado Authorization y omite por completo el flujo OAuth:
Una conexión con clave se diferencia de una OAuth en tres aspectos que vale la pena conocer:
- Los alcances de la propia clave son los permisos del agente. Lo que marcaste
al crear la clave es lo que recibe el agente: no hay una segunda pantalla de
consentimiento. Con una excepción documentada: algunas herramientas necesitan una
persona con sesión iniciada en lugar de un proyecto, porque las rutas detrás de
ellas identifican a un administrador del proyecto a partir del usuario. Esas nunca
se ofrecen a una conexión con clave, sin importar lo que hayas marcado:
create_project,create_mailbox,delete_mailboxy las cuatro herramientas de claves de API. Usa una conexión OAuth para esas. - Está vinculada a un solo proyecto. El proyecto de la clave es el destino de
cada llamada, y un argumento
projectIdque no coincida se rechaza conPROJECT_FIXEDen lugar de ignorarse silenciosamente. Para actuar en otro proyecto, usa una clave que pertenezca a él. - Es una credencial de proyecto, no personal. No aparece en Configuración → Aplicaciones conectadas, porque no hay ninguna fila de consentimiento detrás. La revocas desde Configuración → Claves de API, y la revocación detiene al agente en su siguiente llamada.
Elegir lo que un agente puede hacer [#choosing-what-an-agent-can-do]
Ambas pantallas que te piden otorgar capacidades (la pantalla de consentimiento OAuth y el diálogo de claves de API) se abren con un ajuste predefinido con nombre y luego te permiten marcar casillas individuales. Un ajuste predefinido es solo una selección inicial; no se almacena nada excepto la lista resultante de permisos.
| Ajuste predefinido | Qué cubre | Permisos | ¿Contiene algo irreversible? |
|---|---|---|---|
| Solo lectura | Ver todo en este proyecto, no cambiar nada. | 18 | No |
| Acceso estándar* *(predeterminado) | Gestionar contactos, plantillas, segmentos y borradores de campañas, y enviarte correos de prueba a ti mismo. No puede enviar correo a nadie más. | 29 | No |
| Envío y campañas | Todo lo del acceso estándar, más enviar correo y ejecutar tus automatizaciones. | 32 | Sí — 3 |
| Acceso completo | Todo, incluidos buzones, nuevos proyectos y claves de API. | 38 | Sí — los 9 |
El acceso estándar es el predeterminado y es deliberadamente una concesión capaz: un agente que gestiona tus contactos, segmentos, plantillas y borradores de campañas, y que no puede poner correo en la bandeja de entrada de nadie. La mayoría de la gente quiere eso y nada más.
Una concesión sin permisos marcados es válida. Significa que el cliente puede iniciar sesión por ti y no aprender nada más.
Conectar un agente de solo lectura [#connecting-a-read-only-agent]
Solo lectura es el ajuste predefinido al que recurrir cuando un agente debe responder preguntas sobre un proyecto y no cambiar nada en él. Dos consecuencias vale la pena conocer antes de elegirlo, y el servidor aplica ambas en lugar de solo documentarlas.
- La lista de herramientas es más corta. Las herramientas se filtran según los
permisos de la conexión antes de mostrarle nada al agente, por lo que a una
conexión de solo lectura nunca se le ofrecen
send_campaign,create_contactniedit_workflow. No puede llamar a lo que no puede ver, y no gasta un turno descubriendo un rechazo. - Se ofrece
diagnose_delivery. La entregabilidad tiene un permiso de lectura propio, que es lo que permite que la pregunta que la gente más le hace a un agente —¿por qué no llegó este correo?— se pueda responder sin otorgar ni una sola escritura.
Dos permisos están deliberadamente fuera. api-keys:read enumera tus credenciales,
por lo que no pertenece a ningún ajuste predefinido pre-marcado: un agente de solo
lectura puede ver tus contactos, pero no lo que tus claves pueden hacer. Y
emails:test está en Acceso estándar en su lugar, porque "solo lectura" es
una promesa sobre el mundo más que sobre nuestra base de datos: un ajuste
predefinido que envía correo, incluso a ti, ha roto la promesa que su nombre hace.
Permisos que necesitan aprobación explícita [#permissions-that-need-explicit-approval]
Nueve permisos pueden producir un efecto que nada en el panel de Sendly deshace. Se muestran sin marcar, con la advertencia siguiente junto a la casilla:
| Permiso | De qué se te advierte |
|---|---|
emails:send | El correo enviado de esta manera llega a bandejas de entrada reales y no se puede recuperar. |
campaigns:send | Esto envía una campaña a toda tu audiencia y no se puede recuperar. |
workflows:write | Un flujo de trabajo habilitado sigue enviando por sí solo, mucho después de esta conversación. |
suppression:write | Eliminar una dirección permite que Sendly envíe correo a alguien que te pidió que te detuvieras. |
projects:write | Los nuevos proyectos cuentan para tu plan y pueden facturarse. |
api-keys:read | Revela qué claves existen y qué puede hacer cada una. |
api-keys:write | Una clave creada aquí sigue funcionando incluso después de que desconectes esta aplicación. |
mailboxes:write | Un nuevo buzón comienza a recibir correo real en tu dominio, y eliminar uno borra todos los mensajes que contiene. |
mailboxes:send | El correo enviado de esta manera llega desde tu propia dirección de soporte y no se puede recuperar. |
Dos de estos merecen una explicación, porque son los que la gente consulta.
api-keys:read no cambia nada: está en la lista por lo que revela, ya que un
mapa de qué credenciales existen y qué puede hacer cada una es un mapa de la
superficie de ataque de tu cuenta. Y campaigns:write no está en la lista:
redactar una campaña y enviarla por correo son permisos separados ahora, por lo que
un agente puede crear una campaña para ti sin poder enviarla.
Modo Código (predeterminado) [#code-mode-default]
Una conexión ve exactamente dos herramientas, no una por operación: search_tools
y execute_typescript. Cada capacidad en Full surface a continuación
sigue existiendo detrás de ellas, accesible de la misma manera, bajo los mismos
permisos: esto cambia cuántas herramientas lista un cliente, no lo que un agente
puede hacer.
| Herramienta | Qué hace |
|---|---|
search_tools | Encuentra las herramientas a las que esta conexión puede acceder y devuelve cada una como una firma TypeScript declare function external_<name>(...), etiquetada como [read-only] o [write] con su título y descripción. Un argumento opcional query reduce el resultado a una coincidencia de subcadena sin distinción de mayúsculas y minúsculas contra el nombre, título o descripción de una herramienta: reduce lo que la conexión ya puede alcanzar y nunca lo amplía. Omítelo para listar todo lo accesible. |
execute_typescript | Ejecuta un programa TypeScript breve, escrito por el agente, en un entorno aislado. El programa llama a las funciones external_* declaradas search_tools —ya están en el ámbito— y debe return su resultado. await Promise.all([...]) ejecuta llamadas independientes en un solo viaje de ida y vuelta en lugar de varios. |
Llamar a external_<name>(...) desde dentro del programa alcanza el mismo manejador que
ejecutaría una llamada directa a esa herramienta: las mismas comprobaciones de autenticación,
alcance, selección de proyecto, confirmación de envío masivo y auditoría, ya sea que el
agente la haya llamado por nombre o mediante execute_typescript. Orquestar tres llamadas en
un solo programa cuesta un viaje de ida y vuelta de MCP en lugar de tres; no hace nada que
tres llamadas de herramienta separadas no pudieran hacer.
search_tools declara solo las herramientas a las que llegan los permisos de esta conexión.
Cualquier otro nombre de external_* simplemente no está definido dentro del programa,
por lo que llamar a uno lanza un ReferenceError en lugar de una negativa codificada.
Una negativa dentro del programa —un proyecto al que no puede dirigirse, una conexión
revocada, un envío masivo sin confirmar, argumentos que no coinciden con la declaración—
se manifiesta como un Error de JavaScript lanzado, no como una forma de resultado
separada: el mensaje dice <CODE>: <details>, por ejemplo CONFIRMATION_REQUIRED: … o INVALID_ARGUMENTS: …,
usando los mismos códigos que Solución de problemas más abajo. Cuando la
negativa lleva campos estructurados (requiredScope, upstreamCode, upstreamStatus),
estos siguen a los detalles como JSON final, por ejemplo
TOOL_EXECUTION_FAILED: … {"upstreamCode":"CONFLICT","upstreamStatus":409}.
El propio try/catch del programa lo ve como cualquier otra excepción,
y la llamada a la herramienta externa no se marca como error: la llamada en sí tuvo
éxito; el código que escribió el agente es lo que falló. Un programa que se ejecuta durante
aproximadamente 30 segundos, incluido un bucle infinito, se detiene y la llamada aún
responde normalmente, informando que no terminó en lugar de colgarse.
Si un cliente no puede orquestar un programa aislado en absoluto, Sendly puede servir la
superficie de una herramienta por operación que se muestra a continuación directamente en su
lugar (MCP_TOOL_SURFACE=full): un interruptor operativo, no algo que una conexión solicite por sí misma.
Superficie completa [#full-surface]
La superficie de una herramienta por operación que execute_typescript orquesta arriba, y la que
Sendly también puede servir directamente. Un agente solo ve las herramientas que cubre su
concesión aquí también: si apruebas analytics:read y nada más, view_analytics y list_projects
son las únicas herramientas a continuación que aparecen: las demás nunca se registran, por lo
que el agente ni siquiera puede intentarlas.
Tus proyectos [#your-projects]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_projects | Lista los proyectos en los que esta conexión puede actuar. Úsalo para elegir el projectId para otras herramientas. | ninguno |
get_project | La configuración del proyecto activo: nombre, región de envío, modo de seguimiento de enlaces, si está deshabilitado | projects:read |
create_project | Crea un nuevo proyecto en tu cuenta. Solo conexiones OAuth: una clave API no tiene un usuario para agregar como miembro | projects:write |
Contactos y segmentos [#contacts-and-segments]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_contacts | Lista contactos, opcionalmente filtrados por correo electrónico o estado de suscripción | contacts:read |
get_contact | Un contacto, con sus campos personalizados | contacts:read |
create_contact | Agrega un contacto | contacts:write |
update_contact | Edita los campos o el estado de suscripción de un contacto | contacts:write |
delete_contact | Elimina un contacto | contacts:write |
list_segments | Lista segmentos | segments:read |
get_segment | Un segmento y su condición | segments:read |
list_segment_contacts | Quién coincide actualmente con un segmento | segments:read |
create_segment | Crea un segmento | segments:write |
update_segment | Edita la condición de un segmento | segments:write |
delete_segment | Elimina un segmento | segments:write |
Plantillas y dominios de envío [#templates-and-sending-domains]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_templates | Lista plantillas de correo electrónico | templates:read |
get_template | Una plantilla, con su cuerpo | templates:read |
create_template | Crea una plantilla | templates:write |
update_template | Edita una plantilla | templates:write |
check_domain | Estado de verificación de tus dominios de envío | domains:read |
add_domain | Registra un dominio de envío y devuelve los registros DNS a publicar | domains:write |
verify_domain | Vuelve a verificar los registros DNS de un dominio y persiste el resultado | domains:write |
start_domain_setup | Inicia la configuración DNS guiada y devuelve un enlace que abres para publicar los registros en tu registrador | domains:write |
Correo electrónico [#email]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_emails | Los correos electrónicos que has enviado, con estado de entrega | emails:read |
get_email | Un correo electrónico y sus eventos | emails:read |
send_test_email | Envía un mensaje de prueba desde la dirección de zona de pruebas del proyecto. Solo puede llegar al correo electrónico de cuenta verificado del propio propietario del proyecto: cualquier otro destinatario es rechazado | emails:test |
send_email | Envía un correo electrónico transaccional. Llega a una bandeja de entrada real y no se puede recuperar | emails:send |
send_test_email es cómo un agente demuestra que el envío funciona sin poder enviar
correo a nadie. No toma ningún argumento from: el remitente es la dirección de
zona de pruebas del proyecto, y la ruta rechaza un cuerpo que nombre uno— y hay un límite
diario en los envíos de zona de pruebas. Es un miembro de Acceso estándar, por lo que
ese ajuste preestablecido puede confirmar tu configuración de extremo a extremo mientras
sigue sin poder poner correo en la bandeja de entrada de un extraño.
Campañas [#campaigns]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_campaigns | Lista campañas | campaigns:read |
get_campaign | Una campaña | campaigns:read |
get_campaign_stats | Los números de entrega y participación de una campaña | campaigns:read |
create_campaign | Crea un borrador de campaña | campaigns:write |
update_campaign | Edita el contenido o la audiencia de un borrador o campaña programada | campaigns:write |
manage_campaign | Cancela, pausa o reanuda una campaña | campaigns:write |
delete_campaign | Elimina una campaña | campaigns:write |
send_campaign | Envía o programa una campaña a su audiencia completa. No se puede recuperar una vez que comienza el envío | campaigns:send |
La protección es del lado del servidor por una razón. Sendly puede pedirle a tu cliente que confirme a través del protocolo, pero este endpoint no mantiene sesión, por lo que esa solicitud no llega a nadie; una protección cuya única aplicación vive en el cliente no es una protección. Requerir una segunda llamada que lleve un argumento adicional es algo que un servidor sin estado puede realmente aplicar. El umbral se mide contra los contactos del proyecto, no contra la audiencia de la campaña. El recuento de audiencia es un número almacenado en caché que un trabajo en segundo plano actualiza, por lo que está desactualizado exactamente cuando importa: una lista recién construida que aún muestra cero. Cada audiencia es un subconjunto de los contactos del proyecto, por lo que este límite no puede ser incorrecto en la dirección peligrosa. Sí pide de más: un envío a un segmento de tres personas dentro de un proyecto grande aún requiere la confirmación, que es la forma correcta de equivocarse en una pregunta cuya respuesta no se puede recordar.
send_email no está cubierto y no necesita estarlo. Acepta un destinatario, por lo que enviar
un correo a mil personas a través de él son mil llamadas visibles en lugar de la única llamada
cuyo radio de explosión el agente nunca tuvo que declarar.
Flujos de trabajo [#workflows]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_workflows | Listar flujos de trabajo de automatización | workflows:read |
get_workflow | Un flujo de trabajo y sus pasos | workflows:read |
get_workflow_status | El estado actual de un flujo de trabajo: habilitado o no, qué lo activa, cuántos pasos tiene, y cómo han ido sus ejecuciones: el total y el recuento de las que están en curso, en espera, completadas, fallidas y canceladas | workflows:read |
list_workflow_executions | Las ejecuciones de un flujo de trabajo, una fila por contacto | workflows:read |
create_workflow | Construir un flujo de trabajo a partir de una especificación: un disparador, su configuración y una lista ordenada de pasos. Se inicia deshabilitado a menos que se indique lo contrario, para que puedas revisarlo antes de que se ejecute | workflows:write |
edit_workflow | Cambiar el nombre, la descripción, el estado habilitado o el disparador de un flujo de trabajo y, opcionalmente, reemplazar toda su secuencia de pasos en la misma llamada | workflows:write |
clone_workflow | Copiar un flujo de trabajo, pasos incluidos, como un nuevo borrador. La copia siempre se inicia deshabilitada; el original no se modifica | workflows:write |
manage_workflow | Pausar o reanudar un flujo de trabajo. Pausar detiene nuevas ejecuciones y cancela las que ya están en curso, informando cuántas terminó | workflows:write |
update_workflow | Editar solo metadatos: nombre, descripción, evento disparador, estado habilitado, reentrada, límite por hora. No puede crear ni reemplazar el grafo de pasos: edit_workflow es la herramienta que puede hacerlo | workflows:write |
delete_workflow | Eliminar un flujo de trabajo y su historial de ejecuciones. Se rechaza con un 409 mientras alguna de sus ejecuciones siga en curso | workflows:write |
manage_workflow tiene exactamente dos acciones, pause y resume. Leer el
estado de un flujo de trabajo solía ser una tercera y ahora es get_workflow_status, lo cual es un
hecho de permisos más que una reorganización: una herramienta declara un permiso y debe poder
alcanzar todo lo que hace; pausar necesita workflows:write, y leer los recuentos de ejecuciones
solo necesita workflows:read. Si se dejara como una sola herramienta, la acción de lectura se
rechazaría precisamente para las conexiones a las que se les otorgó escritura sin lectura.
Dividida, un agente que puede mirar pero no tocar aún puede responder "¿está esta
automatización en ejecución y cuántos contactos hay dentro?".
manage_workflow con pause hace ambas cosas. Detiene nuevas ejecuciones y cancela las
ejecuciones ya en curso, e informa cuántas canceló, para que el agente pueda distinguir "no
había nada en ejecución" de "acabo de detener cuatrocientas jornadas". Cancelar es terminal:
resume reabre el flujo de trabajo a nuevas ejecuciones, no devuelve a los contactos
cancelados a donde estaban.
Este es el borde práctico de la advertencia en workflows:write: un flujo de trabajo habilitado
sigue enviando por sí solo, mucho después de la conversación que lo habilitó.
Construir los pasos de un flujo de trabajo [#building-a-workflows-steps]
create_workflow y edit_workflow aceptan una lista lineal de pasos, que es lo que casi
toda automatización es. El paso disparador se antepone por ti: no lo incluyas, y
pasar steps a edit_workflow reemplaza cada paso existente en lugar de fusionar, que
es por lo que esa herramienta está marcada como destructiva.
Cualquier cosa con una rama es un grafo en lugar de una secuencia, y los grafos se leen y escriben
completos en GET y PUT /api/v1/workflows/{id}/graph — workflows:read y
workflows:write respectivamente. Una respuesta de GET se acepta textualmente por PUT en la
misma ruta, por lo que el viaje de ida y vuelta es: leer el documento, cambiar un paso, enviarlo
todo de vuelta.
{
"workflow_id": "8f1c4d2e-5a7b-4a1e-9c3f-2b6d8e0a1f42",
"version": 7,
"steps": [
{
"id": "1b9f6a30-2c44-4f8e-9a01-77c2d1b5e903",
"type": "TRIGGER",
"name": "Signed up",
"position": { "x": 0, "y": 0 },
"config": { "eventName": "user.signup" },
"template_id": null
},
{
"id": "3d2e7c81-9b05-4a26-8f13-0c5a4e9d6712",
"type": "DELAY",
"name": "Wait a day",
"position": { "x": 0, "y": 160 },
"config": { "amount": 1, "unit": "days" },
"template_id": null
},
{
"id": "5a4b8e12-6d37-4c90-b2e5-1f8c3a70d954",
"type": "SEND_EMAIL",
"name": "Day 1: getting started",
"position": { "x": 0, "y": 320 },
"config": {},
"template_id": "c7e1a904-3b62-4d58-8a17-9e05f2d6b481"
}
],
"transitions": [
{
"id": "9c0d5f73-1a86-42be-9d47-6b3e8a15c027",
"from_step_id": "1b9f6a30-2c44-4f8e-9a01-77c2d1b5e903",
"to_step_id": "3d2e7c81-9b05-4a26-8f13-0c5a4e9d6712",
"condition": null,
"priority": 0
},
{
"id": "2e6a1b48-7f39-4c05-a8d2-53b90c7e6f18",
"from_step_id": "3d2e7c81-9b05-4a26-8f13-0c5a4e9d6712",
"to_step_id": "5a4b8e12-6d37-4c90-b2e5-1f8c3a70d954",
"condition": null,
"priority": 0
}
]
}
Envía ese mismo documento de vuelta a PUT para mantener el flujo de trabajo como está, o cámbialo primero.
Las reglas que sigue el documento:
- Los ids de los pasos son tuyos. Envía de vuelta un id que leíste para conservar ese paso y su historial de ejecuciones, un UUID nuevo para añadir un paso, y omite un paso por completo para eliminarlo junto con su historial.
- Exactamente un paso es el
TRIGGER— el único nodo de entrada del grafo. configse tipa por tipo de paso, entre los nueve tiposTRIGGER,SEND_EMAIL,DELAY,WAIT_FOR_EVENT,CONDITION,EXIT,WEBHOOK,UPDATE_CONTACTySEND_AT_OPTIMAL_TIME. Debido a que el contrato discrimina entype, un SDK generado reduceconfigdesde el tipo que ya conoces. Una clave que el contrato no nombra se pasa tal cual en lugar de eliminarse; una clave cuyo valor es incorrecto —unit: "fortnights", un objetivo de webhook que no es una URL — se rechaza.- Cada borde permanece dentro del documento.
from_step_idyto_step_iddeben nombrar pasos en el mismo payload, y un paso no puede apuntarse a sí mismo.priorityordena los bordes que salen de un paso, de menor a mayor. Los bordes de un pasoCONDITIONllevan{ "branch": "yes" }y{ "branch": "no" }, o el id de la rama en la forma de múltiples ramas. - Como máximo 200 pasos y 400 transiciones.
versionavanza en cada escritura estructural, y cada escritura toma una instantánea del grafo, por lo que un número diferente entre dos lecturas significa que alguien lo editó en el medio.- Una escritura de grafo se rechaza con un 409 mientras el flujo de trabajo tenga ejecuciones en curso,
porque esos contactos están parados en los pasos que se están reemplazando.
POST /api/v1/workflows/{id}/pauselos despeja primero.
Para una secuencia lineal no necesitas estos endpoints en absoluto: POST /api/v1/workflows y
PATCH /api/v1/workflows/{id} ambos aceptan un sequence, que es exactamente lo que
create_workflow y edit_workflow envían, por lo que las dos credenciales construyen el mismo grafo
en lugar de grafos similares.
POST /api/v1/workflows/{id}/clone — la ruta detrás de clone_workflow — copia un flujo de trabajo
y todo su grafo en el lado del servidor, desde una lectura consistente. Eso no es lo mismo que leer
un grafo y escribirlo en un nuevo flujo de trabajo: una copia ensamblada a partir de dos solicitudes puede capturar
una edición que ocurrió entre ellas y materializar un flujo de trabajo que nunca existió.
Analítica y uso [#analytics-and-usage]
| Herramienta | Qué hace | Permiso |
|---|---|---|
view_analytics | Recuentos de enviados, entregados, abiertos y rebotados | analytics:read |
get_usage | Recuentos de envíos de este mes y de hoy frente a tus límites aplicados | usage:read |
Entregabilidad [#deliverability]
| Herramienta | Qué hace | Permiso |
|---|---|---|
diagnose_delivery | Por qué el correo de uno de tus dominios de envío no llega: el estado DKIM, SPF, DMARC y MX del dominio, los contadores recientes de rebotes y quejas del proyecto y — si nombras un destinatario — si esa dirección está suprimida | deliverability:read |
Cada señal en la respuesta ya era legible un endpoint a la vez. Lo que ningún endpoint hacía era decir qué significa la combinación, que es la parte en la que una conversación de soporte realmente se centra: "verificado, pero SPF fallando y 6% de rebotes" es un problema diferente de "no verificado", y distinguirlos a partir de tres payloads separados era un juicio que quien llamaba tenía que hacer sin ayuda.
Entonces la respuesta comienza con findings — peor primero, cada uno con un code estable, una severidad de
blocking, degraded o info, qué está mal y la solución. Un agente se ramifica en el
código, nunca en la redacción. Los códigos son domain_not_registered, domain_not_verified,
recipient_suppressed, spf_failing, dmarc_missing, custom_mail_from_failed,
bounce_rate_critical, bounce_rate_elevated, complaint_rate_critical,
complaint_rate_elevated, no_recent_sends, sample_too_small_for_rates y
dns_never_checked.
Dos cosas para leer las señales crudas. Los estados DNS son los resultados en caché de
el trabajo de verificación de Sendly en lugar de una consulta en vivo, y identity.last_checked_at dice
cuándo se completaron. Los contadores de entrega son del proyecto, en una ventana de 1 a
30 días que por defecto es 7, porque un registro de correo no almacena qué dominio lo envió.
Tiene un permiso propio en lugar de apoyarse en domains:read, porque lee el estado DNS,
los contadores de entrega y la supresión juntos, y una clave a la que se le otorgó "ver tus
dominios de envío" no aceptaba la última de esas. Nada bajo él escribe nada ni revela
nada que un miembro del proyecto no pueda ver ya en el panel, por lo que está pre-marcado desde
Solo lectura hacia arriba.
Limpiar una lista [#cleaning-a-list]
| Herramienta | Qué hace | Permiso |
|---|---|---|
validate_emails | Comprueba hasta 50 direcciones en una sola llamada | validation:write |
clean_list | Inicia una ejecución en segundo plano sobre cada dirección de una lista | validation:write |
get_validation_run | Cuánto ha avanzado una ejecución y qué ha encontrado | validation:read |
list_validation_results | Una página de los veredictos por dirección de una ejecución, filtrable por veredicto | validation:read |
Estas se facturan por dirección comprobada, por eso el permiso de escritura es una casilla propia
en lugar de parte de contacts:write: un agente autorizado para gestionar tus contactos no debería
poder gastar tu dinero recorriendo tu lista. Leer una ejecución terminada no cuesta nada y
se encuentra en Solo lectura.
Cada respuesta incluye un verdict, y es el campo sobre el que decidir. deliverable es seguro para
enviar por correo. undeliverable significa que el dominio no existe o no publica registros MX.
risky significa un proveedor de buzón desechable. unknown significa que el DNS no respondió, por lo que esa dirección
no fue comprobada — es un valor separado de undeliverable a propósito, porque un agente
que fusionara ambos eliminaría contactos activos por un fallo de red.
Los otros campos describen la dirección en lugar de juzgarla. is_personal (un proveedor gratuito de
consumo) y is_role_address (support@, info@) son información de calidad de lista, no
problemas: los clientes reales usan Gmail y las empresas reales responden a su dirección de soporte.
is_disposable es la única marca que baja un veredicto.
clean_list no limpia nada por sí mismo. Valida y se detiene — no se da de baja ninguna
suscripción ni se elimina ningún contacto. Actuar sobre un hallazgo es una llamada separada bajo un
permiso diferente, que es lo que evita que una consulta DNS que puede responder unknown reduzca
silenciosamente una audiencia.
Listas de suscriptores [#subscriber-lists]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_lists | Las listas de suscriptores que mantiene este proyecto, con sus tamaños | lists:read |
get_list | Una lista, con su tamaño y su configuración de doble opt-in | lists:read |
create_list | Crear una lista vacía | lists:write |
update_list | Renombrar una lista o cambiar su configuración | lists:write |
delete_list | Eliminar una lista y cada suscripción en ella | lists:write |
Una lista es una suscripción estática: personas que se añadieron y permanecen hasta que se van. Eso
es lo que la separa de un segmento, que es una condición dinámica sobre campos de contacto, y de
un tema, que es una decisión permanente sobre un asunto. member_count cuenta suscripciones en
cada estado — una invitación pendiente y una exclusión voluntaria son ambas suscripciones — por lo que
es el tamaño de la tabla de suscripciones, no el número de personas que un envío alcanzaría.
Añadir personas a una lista no está en esta superficie. La suscripción es donde comienza el doble opt-in: crea la suscripción como pendiente y genera un token de confirmación cuya entrega es tu trabajo. Un agente que pusiera a alguien en una lista estaría afirmando un consentimiento del que no tiene evidencia, por lo que las herramientas se detienen en la lista misma.
delete_list elimina el registro de consentimiento. Las suscripciones se van con la lista, y una
suscripción dada de baja es la evidencia de que alguien optó por no participar — recrear la lista y
reimportar las mismas direcciones no encontrará sus exclusiones esperando. El correo ya enviado
no se ve afectado.
Temas y consentimiento [#topics-and-consent]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_topics | Los asuntos sobre los que este proyecto envía correo, y cuántas personas respondieron a cada uno | topics:read |
get_contact_topic_preferences | Todo lo que un contacto ha dicho que quiere | topics:read |
create_topic | Añadir un asunto al que las personas pueden suscribirse | topics:write |
update_topic | Renombrar, re-describir, cambiar el valor predeterminado o retirar un tema | topics:write |
set_topic_subscription | Registrar lo que un contacto quiere sobre un tema | topics:write |
Un tema es un asunto sobre el que envías correo — un resumen semanal, un registro de cambios, un aviso de facturación — y la respuesta de un contacto a uno es una decisión permanente en lugar de un filtro de audiencia. Se aplica a cualquier audiencia que seleccione una campaña, por lo que elegir una audiencia diferente no es una forma de evitarlo. Esa es la diferencia entre un centro de preferencias y una casilla que nadie respeta.
set_topic_subscription no puede suscribir a nadie. Pedirle que suscriba deja al
contacto en pending y devuelve un enlace de confirmación; no se envía nada sobre ese tema
hasta que una persona lo abre, y no hay parámetro para omitir el paso. Un agente que afirma que
alguien quiere correo no es evidencia de que lo quiera, y la reputación que cuesta el error es
tuya. Sendly no envía ese correo de confirmación — lo haces tú, desde tu propio dominio verificado.
La exclusión es al revés y tiene efecto de inmediato: retirar el consentimiento nunca debe
ser más difícil que darlo.
default_opt_in decide qué significa el SILENCIO. Si se deja como verdadero, un contacto que nunca ha respondido
cuenta como suscrito — que es la lectura honesta para un tema introducido sobre una lista que ya
tienes, ya que esas personas consintieron en recibir noticias tuyas. Si se establece como falso, la ausencia significa "no
preguntado" y solo cuenta un sí explícito. subscribed_count informa solo respuestas explícitas, por lo que
se lee bajo en un tema default_opt_in; así es cuántas personas respondieron, no cuántas
recibirían el correo.
No hay eliminación. archived: true retira un tema — lo deja fuera del centro de preferencias y
deja de ser enviable — y cada exclusión registrada contra él sobrevive, porque eliminar el
tema eliminaría las elecciones que las personas hicieron sobre él.
Eventos y webhooks [#events-and-webhooks]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_events | Los eventos personalizados que tu aplicación ha registrado | events:read |
record_event | Registrar un evento personalizado contra un contacto existente | events:write |
list_webhooks | Listar endpoints de webhook | webhooks:read |
create_webhook | Añadir un endpoint de webhook | webhooks:write |
update_webhook | Editar un endpoint de webhook | webhooks:write |
delete_webhook | Eliminar un endpoint de webhook | webhooks:write |
Lista de supresión [#suppression-list]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_suppressions | Las direcciones que Sendly se niega a enviar | suppression:read |
add_suppression | Bloquear una dirección | suppression:write |
remove_suppression | Desbloquear una dirección, re-habilitando el envío a ella | suppression:write |
Buzones [#mailboxes]
Los buzones son el lado conversacional: una bandeja de entrada real detrás de una dirección como
support@yourdomain.com, por lo que el correo enviado allí llega a Sendly — y, con su propio
permiso, un agente puede escribir y enviar un nuevo mensaje desde esa dirección.
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_mailboxes | Los buzones en los dominios de este proyecto, con el estado y dominio de cada uno | mailboxes:read |
get_mailbox | Un buzón, más el host, puerto y nombre de usuario IMAP y SMTP para conectar un cliente de correo. La contraseña no está incluida y no se puede leer de vuelta | mailboxes:read |
create_mailbox | Crear un buzón en un dominio verificado | mailboxes:write |
delete_mailbox | Eliminar permanentemente un buzón y cada mensaje que contiene | mailboxes:write |
compose_mailbox_email | Escribir un correo para un buzón: redactar uno desde una breve instrucción, reescribir un borrador que ya tienes, o sugerir líneas de asunto. Devuelve texto y no envía nada — el resultado siempre dice sent: false | mailboxes:read |
send_mailbox_email | Enviar un correo nuevo de texto plano desde la propia dirección de un buzón, a hasta veinte destinatarios. El destinatario puede responder, se enhebra en las conversaciones de ese buzón, y no se puede recuperar. Los destinatarios suprimidos y el correo que el escáner de contenido rechaza son rechazados; un buzón puede enviar 60 mensajes por hora de esta manera | mailboxes:send |
Cinco datos sobre estos que son más fáciles de saber ahora que de descubrir después:
- Ninguna herramienta del agente lee los mensajes de un buzón. El correo que recibe un buzón es correspondencia de terceros, y ningún permiso del vocabulario cubre su lectura.
get_mailboxdevuelve la configuración de conexión, nunca el contenido. - Un buzón no se puede modificar después de crearse. No hay ruta de actualización ni herramienta de actualización, a propósito. Para cambiar una dirección, elimina el buzón y crea el que quieras.
- No se admiten cuotas. Los buzones se crean sin límite de almacenamiento y no hay forma de añadir uno después. La herramienta no ofrece el argumento, y la ruta lo rechaza en lugar de aceptar un valor que nunca aplicaría.
- El dominio debe verificarse primero, y un proyecto puede tener como máximo diez buzones. Ambos casos se rechazan con un
409, no se solucionan silenciosamente. - Redactar y enviar son permisos diferentes.
compose_mailbox_emailsolo necesitamailboxes:readporque no cambia nada: entrega al agente texto para mostrarte. Poner ese texto en la bandeja de entrada de alguien como tu dirección de soporte essend_mailbox_emailbajomailboxes:send, que está separado deemails:senda propósito: un agente autorizado para enviar un recibo desde tu dominio verificado no ha sido autorizado por ello a abrir una conversación como tu mesa de soporte. Llega sin verificar, y un agente bien educado te muestra el borrador y confirma los destinatarios antes de llamarlo.
La eliminación es la herramienta más afilada de esta superficie: cada mensaje que contiene el buzón se borra, Sendly no guarda otra copia, y ni el panel ni el soporte pueden recuperarlo. El correo enviado a la dirección después se rechaza. Por eso mailboxes:write llega sin verificar.
Claves API [#api-keys]
| Herramienta | Qué hace | Permiso |
|---|---|---|
list_api_keys | Qué claves existen, qué puede hacer cada una, cuándo se usó por última vez. No se devuelve ningún secreto: solo los últimos cuatro caracteres existen en algún lugar | api-keys:read |
create_api_key | Crear una nueva clave. El secreto no se devuelve al agente: el resultado lleva un enlace de un solo uso que solo tú puedes abrir | api-keys:write |
rotate_api_key | Reemplazar el secreto de una clave en su lugar, conservando su nombre y permisos. Mismo enlace de un solo uso; el secreto antiguo deja de funcionar inmediatamente | api-keys:write |
revoke_api_key | Revocar permanentemente una clave. Cualquier cosa que aún la use falla en su próxima solicitud, y no se puede restaurar | api-keys:write |
Un agente puede crear y rotar claves, y aun así nunca ve un secreto: consulta Herramientas que te entregan un enlace a continuación para ver cómo funciona. Dos límites merecen expresarse claramente:
-
Una clave nueva no puede ser más amplia que la conexión que la creó.
create_api_keyrequiere una lista explícita de permisos, y cualquier permiso que la conexión no tenga por sí misma se rechaza conSCOPE_ESCALATION. La solicitud se rechaza por completo, nunca se recorta silenciosamente para que encaje, por lo que un agente no puede usarapi-keys:writepara fabricar una capacidad que nunca le concediste. Solo tu propia sesión del panel está exenta, porque un admin de proyecto ya tiene autoridad total sobre su propio proyecto. -
Cada herramienta de esta sección necesita una conexión OAuth. Las cuatro rutas de claves API identifican a un admin de proyecto a partir del usuario con sesión iniciada, y una clave API no lleva ningún usuario, por lo que una conexión con clave nunca podría llamar a una. Por lo tanto, no se ofrecen a una conexión con clave en absoluto: ausentes de su lista de herramientas en lugar de fallar cuando lo intenta. Esta es una propiedad diseñada, no un modo de fallo: una herramienta que un agente no puede usar no debería estar en su lista. Un agente conectado con una clave no puede listar, crear, rotar ni revocar claves.
list_api_keyses la que parece fuera de lugar, por lo que vale la pena decir por qué está aquí. Esta regla trata sobre la forma de la ruta, no sobre el peligro:api-keys:readno es uno de los permisos que requieren aprobación explícita, y simplemente leer no es irreversible, pero la ruta aún requiere un usuario con sesión iniciada y, por lo tanto, la herramienta aún no puede ser utilizada por una clave. Cada otra herramienta retenida en esta guía se retiene por lo que puede hacer; esta se retiene por quién necesita ser.
Herramientas que te entregan un enlace [#tools-that-hand-you-a-link]
Tres herramientas no pueden terminar dentro del agente, y responden con status: "action_required" y una URL para que abras en lugar de un resultado:
| Herramienta | Qué hace el enlace | Cuánto dura |
|---|---|---|
create_api_key | Muestra el secreto de la nueva clave, una vez | 5 minutos |
rotate_api_key | Muestra el nuevo secreto de la clave rotada, una vez | 5 minutos |
start_domain_setup | Configuración DNS guiada en tu registrador, luego te devuelve a Sendly | De corta duración, establecida por la sesión |
Para las dos herramientas de claves, la razón es que un secreto nunca debe entrar en un resultado de herramienta. Cualquier cosa que reciba un agente se escribe en el contexto del modelo, la transcripción del cliente y cada registro por el que pase esa transcripción: una credencial permanente en los tres. Así que el secreto no cruza el límite en absoluto. En su lugar, el enlace es un ticket de un solo uso de cinco minutos, y abrirlo requiere una sesión de Sendly con sesión iniciada que pertenezca a un admin del proyecto: una credencial que ningún agente tiene, y que ni un token OAuth ni una clave API pueden producir. El agente que solicitó la clave no puede leerla, incluido el que acaba de romper tu implementación al rotarla. Tener la URL no es suficiente por sí solo, y un enlace abierto por la persona equivocada se gasta en lugar de honrarse, así que si eso sucede, rota de nuevo.
start_domain_setup usa la misma forma por una razón diferente: publicar registros DKIM, SPF y MX ocurre en tu registrador, donde Sendly no tiene credenciales y nunca las tendrá.
Permisos y consentimiento [#permissions-and-consent]
Durante el flujo OAuth, Sendly te muestra una pantalla de consentimiento que enumera exactamente lo que el cliente está solicitando, con una casilla de verificación para cada uno. Estas son las descripciones que leerás:
| Permiso | Texto de la pantalla de consentimiento | Requiere aprobación explícita |
|---|---|---|
emails:send | Enviar correos electrónicos desde tus dominios verificados | Sí |
emails:read | Ver los correos electrónicos que has enviado y su estado de entrega | No |
contacts:read | Ver tus contactos y sus campos personalizados | No |
contacts:write | Crear, actualizar y eliminar tus contactos | No |
campaigns:read | Ver tus campañas y su rendimiento | No |
campaigns:write | Crear, editar y organizar tus campañas | No |
segments:read | Ver tus segmentos y quién pertenece a ellos | No |
segments:write | Crear, editar y eliminar tus segmentos | No |
workflows:read | Ver tus flujos de automatización y sus ejecuciones | No |
workflows:write | Crear, editar, habilitar y eliminar tus flujos de automatización | Sí |
templates:read | Ver tus plantillas de correo electrónico | No |
templates:write | Crear, editar y eliminar tus plantillas de correo electrónico | No |
domains:read | Ver tus dominios de envío y su estado de verificación | No |
domains:write | Añadir y eliminar dominios de envío, y activar la verificación | No |
webhooks:read | Ver tus endpoints de webhook y su historial de entrega | No |
webhooks:write | Crear, editar y eliminar tus endpoints de webhook | No |
suppression:read | Ver las direcciones en tu lista de supresión | No |
suppression:write | Añadir y eliminar direcciones en tu lista de supresión | Sí |
analytics:read | Ver tus análisis de envío y métricas de participación | No |
usage:read | Ver tus totales de uso y límites de facturación | No |
events:read | Ver los eventos personalizados que tu aplicación ha registrado | No |
events:write | Registrar eventos personalizados para tus contactos | No |
projects:read | Ver tus proyectos y sus configuraciones | No |
projects:write | Crear nuevos proyectos en tu cuenta | Sí |
api-keys:read | Ver qué claves API existen, incluido lo que cada una puede hacer | Sí |
api-keys:write | Crear, rotar y revocar claves API — estas siguen funcionando incluso después de desconectar esta aplicación | Sí |
campaigns:send | Enviar o programar tus campañas a su audiencia | Sí |
mailboxes:read | Ver los buzones en tus dominios y sus configuraciones | No |
mailboxes:write | Crear y eliminar buzones en tus dominios verificados | Sí |
emails:test | Enviar correos electrónicos de prueba a tu propia dirección desde el sandbox de Sendly | No |
deliverability:read | Comprobar por qué el correo de uno de tus dominios no llega | No |
mailboxes:send | Escribir y enviar nuevos correos electrónicos desde tus buzones alojados, como esa dirección | Sí |
validation:read | Ver tus ejecuciones de validación de correo electrónico y sus resultados | No |
validation:write | Comprobar si las direcciones de correo electrónico pueden recibir correo — esto se factura por dirección | No |
topics:read | Ver los temas sobre los que envías correo y quién está suscrito a cada uno | No |
topics:write | Crear y editar temas, y cambiar a qué están suscritos tus contactos — esto decide a quién llegan tus campañas | No |
lists:read | Ver tus listas de suscriptores y quién está en ellas | No |
lists:write | Crear, renombrar y eliminar tus listas de suscriptores | No |
Nada sucede en tu cuenta hasta que lo apruebas, y ninguna herramienta se ejecuta nunca bajo un permiso que no hayas otorgado.
Cada permiso en esta tabla tiene al menos un endpoint detrás, así que nada de lo que otorgues
aquí es inerte. Dos de ellos no tienen aún una HERRAMIENTA DE AGENTE: lists:read y lists:write gobiernan
los endpoints de /api/v1/lists, que una clave API o un token OAuth pueden llamar directamente, y
la superficie MCP no ofrece una herramienta de listado. Otorgarlos a una conexión de agente hoy
por tanto amplía lo que un token podría hacer por HTTP y no cambia nada a lo que el propio agente puede
alcanzar — lo cual vale la pena saber antes de marcarlos.
Elegir un proyecto [#choosing-a-project]
Cada herramienta excepto list_projects opera en un proyecto.
- Una conexión OAuth cubre cada proyecto al que perteneces, y cada herramienta toma un
projectIdopcional. ¿Perteneces a exactamente uno? Omítelo; Sendly lo infiere. ¿Perteneces a varios? El agente debe pasar uno, o la llamada se rechaza conPROJECT_REQUIREDy se le indica que llame alist_projectsprimero. Los agentes bien comportados hacen esto por su cuenta. UnprojectIdque no sea uno de tus proyectos recibe el mismoPROJECT_REQUIREDantes de que la herramienta haga algo, redactado de manera idéntica tanto si ese proyecto existe como si no. - Una conexión de clave API está vinculada al proyecto propio de la clave. El argumento no se
ofrece en absoluto, y un cliente que lo envíe de todos modos es rechazado con
PROJECT_FIXED.
Sendly rechaza en lugar de adivinar en ambos casos a propósito: elegir silenciosamente "el
primer" proyecto, o ignorar silenciosamente un projectId que el agente creía estar usando,
significaría actuar sobre los datos del inquilino equivocado.
Cambiar de opinión [#changing-your-mind]
Para retirar un permiso, ve a Configuración → Aplicaciones conectadas y desmárcalo. La conexión permanece; el agente conserva todo lo demás.
Para terminar la conexión por completo, elige Desconectar en la misma página. Para una conexión de clave, revoca la clave en Configuración → Claves API en su lugar.
Cada llamada de herramienta vuelve a comprobar tu concesión en vivo antes de ejecutarse, así que un permiso retirado comienza a ser rechazado **de inmediato** — incluso aunque el token de acceso del agente no haya expirado — y desconectar detiene al agente por completo en su siguiente llamada.La lista de herramientas se actualiza poco después. El listado de un agente se construye a partir del token que
tiene, así que una herramienta retirada puede seguir apareciendo allí hasta que ese token sea reemplazado:
cada llamada a ella es rechazada con SCOPE_MISSING mientras tanto, así que ninguna autoridad
sobrevive al cambio. La lectura del token usa la misma concesión en vivo que la puerta, lo que
significa que la herramienta retirada desaparece del listado tan pronto como el agente se actualiza —
dentro de una hora, ya que los tokens de acceso duran ese tiempo — e inmediatamente si se reconecta.
Una actualización presentada después de una desconexión completa es rechazada directamente en lugar de ser honrada.
Solución de problemas [#troubleshooting]
Los fallos vuelven al agente como resultados de herramienta que llevan un código, no como errores de transporte, así que el agente puede explicártelos en lugar de simplemente soltar la conexión.
| Lo que ves | Qué significa | Solución |
|---|---|---|
401 desde el endpoint | No se presentó una credencial válida | Ejecuta el flujo OAuth, o coloca una clave sk_… válida en el encabezado Authorization. Una clave pk_… o una sesión de navegador no serán aceptadas |
SCOPE_MISSING | A esta conexión nunca se le otorgó ese permiso, o fue retirado — o la clave es anterior a los permisos por capacidad y la herramienta es irreversible | Vuelve a aprobarla en Configuración → Aplicaciones conectadas, o crea una nueva clave en Configuración → Claves API con los permisos marcados |
CONSENT_REVOKED | La conexión fue desconectada de tu cuenta de Sendly | Reconecta la aplicación desde Configuración → Aplicaciones conectadas |
KEY_REVOKED | La clave API que usa esta conexión fue revocada o rotada | Reconecta con una clave actual desde Configuración → Claves API |
PROJECT_REQUIRED | Tu cuenta tiene más de un proyecto (o ninguno), por lo que el destino es ambiguo — o el projectId pasado no es uno de tus proyectos | Haz que el agente llame a list_projects y pase el id elegido como projectId |
PROJECT_FIXED | A una conexión con clave API se le dio un projectId, pero una clave está vinculada a un solo proyecto | Elimina el argumento, o usa una clave que pertenezca al otro proyecto |
USER_DECLINED | Tu cliente te pidió confirmar una acción irreversible y dijiste que no. No se hizo nada — la negativa ocurre antes de que se llame a Sendly en absoluto | Nada que solucionar. Dile al agente qué te gustaría en su lugar |
CONFIRMATION_REQUIRED | Se llamó a send_campaign en un proyecto con más de 1,000 contactos sin confirm: true. No se envió nada | Haz que el agente te diga a quién llega la campaña y qué dice, luego llama de nuevo con confirm: true |
INVALID_ARGUMENTS | Los argumentos no pueden producir una llamada — una regla de campos cruzados de la propia herramienta los rechazó, por ejemplo send_email dado un fromName sin from. No se hizo nada | El mensaje dice qué cambiar. No reintentes los mismos argumentos: producen la misma negativa |
SCOPE_ESCALATION | create_api_key solicitó un permiso que esta conexión no posee por sí misma | Solicita una clave cuyos permisos sean un subconjunto de lo que otorgaste al agente, o crea la clave tú mismo en Configuración → Claves API |
TOOL_EXECUTION_FAILED | La llamada llegó a Sendly pero no pudo completarse | Reintenta. Si persiste, contacta a support@sendly.now |
La anotación destructive que publica Sendly marca una cosa más específica, y vale la pena
saber cuál: una herramienta que borra o sobrescribe algo que ya existía —
delete_contact, edit_workflow (cuyos steps reemplazan cada paso existente),
revoke_api_key (que invalida un secreto activo), delete_list (que lleva consigo las
membresías). Un envío no está marcado como destructivo, porque no destruye
nada; es irreversible en la otra dirección, y ninguna anotación captura eso.
No leas una herramienta no marcada como una segura.
Sendly también puede preguntar a través del protocolo, y USER_DECLINED es la
respuesta que produce una negativa, pero solo los clientes en un transporte que lleva una
conversación con ámbito de sesión lo mostrarán; en el endpoint actual esa solicitud no puede
entregarse, por lo que no aparece ningún aviso propio de Sendly. Nada depende de ello: el
permiso que marcaste en la pantalla de consentimiento es la concesión, y cada herramienta
interactiva se completa devolviendo un enlace.
La única confirmación que Sendly impone por sí mismo es la protección de envío
masivo: por encima de 1,000 contactos, send_campaign requiere una segunda llamada
que lleve confirm: true. Esa funciona en este transporte precisamente porque pide un
argumento en lugar de una conversación.
Cómo se relaciona con el resto de la plataforma [#how-it-relates-to-the-rest-of-the-platform]
El servidor MCP no es un backend separado. Cada llamada de herramienta sale a través de la
propia API REST pública de Sendly llevando la misma credencial con la que te conectaste, por lo que
las mismas verificaciones de alcance, reglas de membresía y reglas de proyecto deshabilitado se aplican a un agente como a
curl o los SDK. No hay atajo privilegiado.