Referencia de la API REST de NetSendo
Todos los endpoints de la API pública, con autenticación, scopes, límites de solicitudes, errores y ejemplos.
Escrita para NetSendo 2.7.0 y contrastada con su código fuente (rutas, controladores y el modelo de clave API).
Visión general
La API forma parte de todas las instalaciones de NetSendo, tanto SILVER como GOLD. Se ejecuta en tu propio servidor en https://your-domain.com/api/v1, usa JSON y actúa sobre la cuenta a la que pertenece la clave API. El servidor MCP y el nodo de n8n usan los mismos endpoints. Las pocas llamadas de funciones GOLD, como los tests A/B, responden 402 sin una licencia GOLD activa.
Envía en cada solicitud Authorization: Bearer con tu clave y Accept: application/json para que los errores de validación lleguen como JSON, y además Content-Type: application/json cuando la solicitud lleve cuerpo.
Comprueba tu clave
GET /api/v1/account devuelve la cuenta asociada a la clave y la versión de NetSendo. Las integraciones lo usan para probar la conexión.
curl https://your-domain.com/api/v1/account \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Accept: application/json"
# 200 OK
{
"data": {
"id": 1,
"name": "Anna Admin",
"email": "admin@example.com",
"version": "2.7.0"
}
}Autenticación y claves API
Crea las claves en el panel de NetSendo, en Configuración → Claves API. Ponle un nombre a cada clave, elige sus scopes y, si quieres, una fecha de caducidad. La clave se muestra una sola vez, al crearla; NetSendo solo guarda su hash SHA-256 y registra cuándo se usó por última vez.
Las claves tienen la forma ns_live_ seguido de 32 caracteres aleatorios. Pasa la clave en el encabezado Authorization como token Bearer. No se aceptan claves en los parámetros de la URL.
Authorization: Bearer ns_live_YOUR_KEYMarca en la clave la opción Clave MCP para que la prueba de conexión MCP integrada pueda usarla. Para conectar asistentes de IA, consulta la documentación del servidor MCP.
Cuando falla la autenticación
La API responde 401 con uno de estos mensajes:
Missing or invalid Authorization header. Use: Bearer <api_key>Invalid API key format. Key should start with ns_live_Invalid API keyAPI key has expired
Scopes
Cada clave tiene un conjunto de scopes. Un endpoint que requiere un scope que la clave no tiene responde 403 Forbidden.
| Scope | Qué permite |
|---|---|
| subscribers:read | Leer la lista de supresión, exportar miembros de una lista en la propia respuesta, leer el historial de actividad de un suscriptor |
| subscribers:write | Crear, actualizar y eliminar suscriptores, creación por lotes, reemplazar las etiquetas de un suscriptor, añadir y quitar direcciones de la lista de supresión |
| lists:read | Informes de higiene de listas y verificación de direcciones, vista previa de importación, actividad e interacción de una lista, horario de envío, valores predeterminados de listas, formularios, emails del sistema y páginas del sistema |
| lists:write | Crear, cambiar y eliminar listas; importar; limpiar y deduplicar; cambios masivos de membresía; etiquetas y campos personalizados; horario de envío y valores predeterminados de listas; formularios; emails y páginas del sistema |
| tags:read | Se puede seleccionar; en 2.7.0 ningún endpoint lo requiere (para leer etiquetas basta una clave válida) |
| notifications:write | Crear notificaciones en el centro de notificaciones del titular de la cuenta |
| webhooks:read | Se puede seleccionar; en 2.7.0 ningún endpoint lo requiere (para leer webhooks basta una clave válida) |
| webhooks:write | Crear, cambiar, eliminar y probar webhooks, y regenerar su secreto de firma |
| email:read | Estado de los emails enviados mediante la API, lista de buzones de envío |
| email:write | Enviar emails individuales y por lotes |
| sms:read | Estado de los SMS enviados mediante la API, lista de proveedores SMS |
| sms:write | Enviar SMS individuales y por lotes |
| messages:read | Vista previa de campañas y número de destinatarios, plantillas de email, categorías de plantillas y bloques guardados |
| messages:write | Crear, cambiar, eliminar, programar, enviar, probar y duplicar campañas; tests A/B; plantillas y bloques guardados |
| funnels:read | Reglas de automatización, sus opciones y registros |
| funnels:write | Crear, cambiar, eliminar, activar y pausar embudos y sus pasos, inscribir suscriptores; crear y cambiar reglas de automatización |
- Un scope de escritura incluye el scope de lectura del mismo recurso: una clave con
lists:writetambién puede llamar a endpoints que requierenlists:read. - Una clave creada sin seleccionar ningún scope recibe los 16 scopes.
- Los endpoints marcados como cualquier clave válida en las tablas de abajo solo comprueban que la clave sea válida y no haya caducado. Entre ellos están listar y leer suscriptores, listas, etiquetas, campos personalizados, campañas, embudos, tests A/B y webhooks. Cada endpoint devuelve solo los datos de la cuenta a la que pertenece la clave.
Límites de solicitudes
La API admite 3.000 solicitudes por minuto por clave API. Las rutas sin clave (los endpoints de suscripción a listas y la descarga firmada de exportaciones) se cuentan por dirección IP con el mismo límite.
Las respuestas incluyen X-RateLimit-Limit y X-RateLimit-Remaining. Si se supera el límite, la API responde 429 Too Many Requests con un encabezado Retry-After en segundos.
Para trabajos grandes, usa los endpoints por lotes en lugar de muchas llamadas individuales: hasta 1.000 suscriptores por POST /subscribers/batch, 5.000 filas por importación y 5.000 contactos por operación de membresía.
Errores
Los errores son objetos JSON con una etiqueta breve error y un message legible:
{
"error": "Forbidden",
"message": "API key does not have subscribers:write permission"
}Los errores de validación usan el formato estándar de Laravel: un message y un objeto errors con un array de mensajes por campo. Envía Accept: application/json; sin él, una validación fallida puede responder con una redirección en lugar de JSON.
{
"message": "The email field must be a valid email address.",
"errors": {
"email": ["The email field must be a valid email address."]
}
}Desde NetSendo 2.4.0, las llamadas de funciones GOLD responden 402 Payment Required sin una licencia GOLD activa (sin clave, SILVER o GOLD caducada). La respuesta indica qué función se rechazó; message está en el idioma predeterminado de la instancia (APP_LOCALE):
{
"error": "Payment Required",
"code": "gold_required",
"message": "“A/B tests” requires the GOLD licence. Upgrade on the Licence page to use it.",
"feature": "ab_tests",
"required_plan": "GOLD",
"upgrade_url": "https://your-domain.com/license"
}| Estado | Significado |
|---|---|
| 200 | Correcto |
| 201 | Creado |
| 202 | Aceptado y en cola (emails, SMS, exportación CSV) |
| 401 | Clave API ausente, mal formada, desconocida o caducada |
| 402 | La llamada usa una función GOLD y la instalación no tiene una licencia GOLD activa |
| 403 | La clave no tiene el scope que requiere el endpoint |
| 404 | El recurso no existe en esta cuenta |
| 409 | Conflicto, por ejemplo al eliminar una lista que aún tiene miembros sin confirm=1, o al iniciar un embudo o un test A/B en un estado incorrecto |
| 422 | La validación falló, o el recurso no está listo (una campaña sin listas, buzón o contenido) |
| 429 | Límite de solicitudes superado |
| 500 | Error del servidor; los detalles están en el log de la instancia |
Paginación
Los endpoints que devuelven colecciones entregan por defecto páginas de 25 elementos (etiquetas: 50). Cambia el tamaño con per_page y avanza con page. La respuesta trae los elementos en data, los enlaces de página en links y contadores como current_page, per_page y total en meta. La exportación de listas en la propia respuesta pagina con un cursor: pasa limit (como máximo 5.000) y, mientras has_more sea true, el next_cursor devuelto.
Endpoints
Todas las rutas de abajo son relativas a tu instancia, por ejemplo https://your-domain.com/api/v1/subscribers. Sustituye las partes entre llaves por IDs de tu cuenta. Las filas marcadas GOLD necesitan una licencia GOLD activa y sin ella responden 402; las descripciones de los grupos indican las llamadas que necesitan GOLD solo para algunos valores.
- Cuenta y prueba de conexión
- Suscriptores
- Listas de contactos
- Importación y exportación
- Higiene de listas
- Membresía de listas (masiva)
- Actividad e interacción
- Lista de supresión
- Etiquetas y campos personalizados
- Envío de emails
- Envío de SMS
- Campañas (messages)
- Tests A/B
- Embudos
- Reglas de automatización
- Webhooks
- Plantillas y bloques guardados
- Emails y páginas del sistema
- Formularios de suscripción
- Notificaciones
- Endpoints auxiliares para integraciones
- NetSendo Brain
- Endpoints de suscripción a listas
Cuenta y prueba de conexión
Identifica la cuenta asociada a una clave. /api/mcp/test es la comprobación de conexión que usan los clientes MCP.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/account | cualquier clave válida |
| GET | /api/mcp/test | cualquier clave válida |
Suscriptores
Crea, lee, actualiza y elimina contactos. POST /subscribers requiere contact_list_id, además de email para una lista de email o phone para una lista SMS; los campos opcionales son first_name, last_name, status, source, tags (IDs de etiquetas), custom_fields, ip_address, user_agent y device. Si la dirección ya existe, se añade a la lista o se reactiva en lugar de duplicarse. Filtra GET /subscribers con contact_list_id, status, email (coincidencia parcial), tag_id, sort_by y sort_order. POST /subscribers/{id}/tags reemplaza todas las etiquetas del suscriptor. La eliminación es lógica (soft delete).
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/subscribers | cualquier clave válida |
| POST | /api/v1/subscribers | subscribers:write |
| POST | /api/v1/subscribers/batch | subscribers:write |
| GET | /api/v1/subscribers/{id} | cualquier clave válida |
| GET | /api/v1/subscribers/by-email/{email} | cualquier clave válida |
| PUT, PATCH | /api/v1/subscribers/{id} | subscribers:write |
| DELETE | /api/v1/subscribers/{id} | subscribers:write |
| POST | /api/v1/subscribers/{id}/tags | subscribers:write |
| GET | /api/v1/subscribers/{id}/activity | subscribers:read |
Listas de contactos
Gestiona listas de email y SMS. PUT fusiona los ajustes: los campos que no envíes no cambian. Los ajustes incluyen double_opt_in, default_mailbox_id, default_sms_provider_id, max_subscribers, resubscription_behavior, signups_blocked, webhook_url y webhook_events. Eliminar una lista con miembros responde 409 hasta que pases confirm=1; los suscriptores se conservan. /stats devuelve los miembros por estado, la interacción, el crecimiento en 30 días y los ajustes que afectan al envío.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/lists | cualquier clave válida |
| POST | /api/v1/lists | lists:write |
| GET | /api/v1/lists/{id} | cualquier clave válida |
| PUT, PATCH | /api/v1/lists/{id} | lists:write |
| DELETE | /api/v1/lists/{id} | lists:write |
| GET | /api/v1/lists/{id}/stats | cualquier clave válida |
| GET | /api/v1/lists/{id}/subscribers | cualquier clave válida |
| GET | /api/v1/lists/{id}/cron-settings | lists:read |
| PUT | /api/v1/lists/{id}/cron-settings | lists:write |
| GET | /api/v1/settings/list-defaults | lists:read |
| PUT | /api/v1/settings/list-defaults | lists:write |
Importación y exportación
Importa CSV, TSV, JSON o una simple lista de direcciones (hasta 5.000 filas por solicitud) con mapeo de columnas y opciones de seguridad, como omitir direcciones no válidas, desechables, suprimidas o genéricas y corregir errores en los dominios. Comprueba antes la vista previa con /import/preview. GET /export devuelve los miembros en la propia respuesta como JSON, CSV o NDJSON con paginación por cursor; POST /export pone en cola una exportación CSV completa y envía al titular de la cuenta un enlace de descarga.
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/import/preview | lists:read |
| POST | /api/v1/lists/{id}/import | lists:write |
| GET | /api/v1/lists/{id}/export | subscribers:read |
| GET | /api/v1/lists/{id}/export/fields | cualquier clave válida |
| POST | /api/v1/lists/{id}/export | cualquier clave válida |
| GET | /api/v1/exports/download | ninguna (URL firmada) |
Higiene de listas
GET /hygiene puntúa una lista de 0 a 100 y cuenta categorías de problemas como sintaxis no válida, dominios con errores, dominios desechables, direcciones genéricas, duplicados, rebotes duros, contactos que nunca interactuaron y contactos inactivos. clean da de baja, quita de la lista, etiqueta, elimina o suprime las categorías elegidas; dedupe fusiona contactos que apuntan al mismo buzón; verify comprueba la sintaxis y los registros MX. clean y dedupe usan dry_run=true por defecto, y las acciones destructivas requieren confirm=true.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/lists/hygiene-options | cualquier clave válida |
| GET | /api/v1/lists/{id}/hygiene | lists:read |
| POST | /api/v1/lists/{id}/hygiene/clean | lists:write |
| POST | /api/v1/lists/{id}/hygiene/dedupe | lists:write |
| POST | /api/v1/lists/{id}/hygiene/verify | lists:read |
Membresía de listas (masiva)
Añade contactos existentes a una lista, quítalos, cambia su estado, muévelos o cópialos a otra lista, o añade y quita etiquetas, hasta 5.000 contactos por llamada. Selecciona los contactos con subscriber_ids, emails o un filter (estado, etiquetas, interacción, fecha de alta). Mover y copiar solo transfieren los contactos activos en la lista de origen y requieren listas del mismo canal. Pasa trigger_automations: false para mover personas sin reiniciar las secuencias de bienvenida.
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/members | lists:write |
| POST | /api/v1/lists/{id}/members/remove | lists:write |
| POST | /api/v1/lists/{id}/members/status | lists:write |
| POST | /api/v1/lists/{id}/members/move | lists:write |
| POST | /api/v1/lists/{id}/members/copy | lists:write |
| POST | /api/v1/lists/{id}/members/tags | lists:write |
Actividad e interacción
/activity reúne en un solo feed las altas, confirmaciones, bajas, aperturas, clics y resultados de envío de una lista, filtrable por days, limit y types[]. /engagement devuelve la composición de la audiencia, el crecimiento y el abandono con una serie diaria, las tasas de apertura y clic, los mejores mensajes y enlaces, y el tamaño de la parte inactiva de la lista.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/lists/{id}/activity | lists:read |
| GET | /api/v1/lists/{id}/engagement | lists:read |
Lista de supresión
Una lista de direcciones a las que no se envía, válida para toda la cuenta y respetada por cada importación. POST acepta emails[], un reason opcional y unsubscribe_existing (true por defecto, da de baja la dirección de todas las listas). DELETE levanta el bloqueo, pero no vuelve a suscribir a nadie.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/suppressions | subscribers:read |
| POST | /api/v1/suppressions | subscribers:write |
| DELETE | /api/v1/suppressions | subscribers:write |
Envío de emails
POST /email/send pone en cola un email: email, subject y content (HTML) son obligatorios; preheader, plain_text, mailbox_id, subscriber_id, schedule_at, tracking_enabled y headers adicionales son opcionales. POST /email/batch envía un mensaje a una lista (list_id o contact_list_ids), a tag_ids o a subscriber_ids, con excluded_list_ids opcional. Ambos responden 202 con un ID que puedes pasar a /email/status/{id}.
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/email/send | email:write |
| POST | /api/v1/email/batch | email:write |
| GET | /api/v1/email/status/{id} | email:read |
| GET | /api/v1/email/mailboxes | email:read |
Envío de SMS
POST /sms/send pone en cola un SMS: phone y message (hasta 1.600 caracteres) son obligatorios; provider_id, subscriber_id y schedule_at son opcionales. POST /sms/batch envía a una list_id, a tag_ids o a subscriber_ids. Los marcadores como [[fname]] se rellenan para cada destinatario.
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/sms/send | sms:write |
| POST | /api/v1/sms/batch | sms:write |
| GET | /api/v1/sms/status/{id} | sms:read |
| GET | /api/v1/sms/providers | sms:read |
Campañas (messages)
En la API las campañas se llaman messages, y cada ruta /messages también funciona bajo /campaigns. Crea una con subject, channel (email o sms) y type (broadcast o autoresponder), define las listas de destinatarios y las exclusiones, y envíala o prográmala. Enviar y programar responden 422 mientras la campaña no tenga lista, buzón (email) o contenido. schedule acepta scheduled_at y un timezone opcional. Filtra el listado con channel, type, status y search. Guardar una campaña con un ab_test_config activo de dos o más variantes necesita GOLD; sin licencia la API responde 402 antes de guardar nada.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/messages | cualquier clave válida |
| POST | /api/v1/messages | messages:write |
| GET | /api/v1/messages/{id} | cualquier clave válida |
| PUT, PATCH | /api/v1/messages/{id} | messages:write |
| DELETE | /api/v1/messages/{id} | messages:write |
| POST | /api/v1/messages/{id}/lists | messages:write |
| POST | /api/v1/messages/{id}/exclusions | messages:write |
| POST | /api/v1/messages/{id}/schedule | messages:write |
| POST | /api/v1/messages/{id}/send | messages:write |
| POST | /api/v1/messages/{id}/test | messages:write |
| GET, POST | /api/v1/messages/{id}/preview | messages:read |
| GET | /api/v1/messages/{id}/stats | cualquier clave válida |
| GET | /api/v1/messages/{id}/recipients-count | messages:read |
| POST | /api/v1/messages/{id}/duplicate | messages:write |
| POST | /api/v1/messages/{id}/toggle-active | messages:write |
| POST | /api/v1/messages/{id}/resend-failed | messages:write |
| POST | /api/v1/messages/{id}/send-to-missed | messages:write |
Tests A/B
Crea un test para una campaña, añade variantes, inícialo y finalízalo, y lee los resultados. Crear un test, añadir variantes e iniciarlo necesitan GOLD; finalizarlo, leer sus resultados y borrarlo funcionan en todos los planes, así que un test que ya estaba en marcha termina aunque la licencia GOLD caduque.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/ab-tests | cualquier clave válida |
| POST | /api/v1/ab-tests | messages:writeGOLD |
| GET | /api/v1/ab-tests/{id} | cualquier clave válida |
| POST | /api/v1/ab-tests/{id}/variants | messages:writeGOLD |
| POST | /api/v1/ab-tests/{id}/start | messages:writeGOLD |
| POST | /api/v1/ab-tests/{id}/end | messages:write |
| GET | /api/v1/ab-tests/{id}/results | cualquier clave válida |
| DELETE | /api/v1/ab-tests/{id} | messages:write |
Embudos
Secuencias de automatización con pasos. Un embudo se inicia con list_signup, tag_added, form_submit o manual. Añade, cambia y quita pasos, activa o pausa el embudo, inscribe a un suscriptor a mano (el embudo debe estar activo; si no, 409) y lee sus estadísticas. Los embudos forman parte de SILVER; añadir un paso de tipo split (división A/B) o convertir un paso en uno necesita GOLD, y los pasos split que ya tiene un embudo siguen siendo editables.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/funnels | cualquier clave válida |
| POST | /api/v1/funnels | funnels:write |
| GET | /api/v1/funnels/{id} | cualquier clave válida |
| PUT, PATCH | /api/v1/funnels/{id} | funnels:write |
| DELETE | /api/v1/funnels/{id} | funnels:write |
| POST | /api/v1/funnels/{id}/steps | funnels:write |
| PUT | /api/v1/funnels/{id}/steps/{step} | funnels:write |
| DELETE | /api/v1/funnels/{id}/steps/{step} | funnels:write |
| POST | /api/v1/funnels/{id}/subscribers | funnels:write |
| POST | /api/v1/funnels/{id}/activate | funnels:write |
| POST | /api/v1/funnels/{id}/pause | funnels:write |
| GET | /api/v1/funnels/{id}/stats | cualquier clave válida |
Reglas de automatización
Reglas del tipo: cuando ocurre un disparador, si se cumplen las condiciones, se ejecutan acciones. /automations/options lista los disparadores, condiciones y acciones disponibles. Las reglas se pueden activar, desactivar y duplicar, y se pueden leer sus registros de ejecución.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/automations/options | funnels:read |
| GET | /api/v1/automations | funnels:read |
| POST | /api/v1/automations | funnels:write |
| GET | /api/v1/automations/{id} | funnels:read |
| PUT, PATCH | /api/v1/automations/{id} | funnels:write |
| DELETE | /api/v1/automations/{id} | funnels:write |
| POST | /api/v1/automations/{id}/toggle | funnels:write |
| POST | /api/v1/automations/{id}/duplicate | funnels:write |
| GET | /api/v1/automations/{id}/logs | funnels:read |
Webhooks
Registra URLs que reciben notificaciones de eventos firmadas. El secreto de firma solo se devuelve al crear el webhook o al regenerar su secreto. /webhooks/events lista los nombres de eventos y /test envía una entrega de prueba. La documentación de webhooks describe cada evento, su payload y cómo verificar las firmas.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/webhooks/events | cualquier clave válida |
| GET | /api/v1/webhooks | cualquier clave válida |
| POST | /api/v1/webhooks | webhooks:write |
| GET | /api/v1/webhooks/{id} | cualquier clave válida |
| PUT, PATCH | /api/v1/webhooks/{id} | webhooks:write |
| DELETE | /api/v1/webhooks/{id} | webhooks:write |
| POST | /api/v1/webhooks/{id}/test | webhooks:write |
| POST | /api/v1/webhooks/{id}/regenerate-secret | webhooks:write |
Plantillas y bloques guardados
Plantillas de email, sus categorías y los bloques guardados del editor de emails. /templates/{id}/preview renderiza una plantilla.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/templates | messages:read |
| POST | /api/v1/templates | messages:write |
| GET | /api/v1/templates/{id} | messages:read |
| PUT, PATCH | /api/v1/templates/{id} | messages:write |
| DELETE | /api/v1/templates/{id} | messages:write |
| POST | /api/v1/templates/{id}/duplicate | messages:write |
| POST | /api/v1/templates/{id}/preview | messages:read |
| GET | /api/v1/template-categories | messages:read |
| GET | /api/v1/template-blocks/types | messages:read |
| GET | /api/v1/template-blocks | messages:read |
| POST | /api/v1/template-blocks | messages:write |
| PUT, PATCH | /api/v1/template-blocks/{id} | messages:write |
| DELETE | /api/v1/template-blocks/{id} | messages:write |
Emails y páginas del sistema
Los emails y páginas que NetSendo muestra en el alta, la confirmación y la baja, identificados por slug. Sin list_id trabajas sobre el predeterminado global; con list_id la primera escritura crea una versión propia para esa lista, y DELETE la quita para que la lista vuelva al predeterminado. Los predeterminados globales no se pueden eliminar.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/system-emails | lists:read |
| GET | /api/v1/system-emails/{slug} | lists:read |
| PUT | /api/v1/system-emails/{slug} | lists:write |
| PUT | /api/v1/system-emails/{slug}/active | lists:write |
| DELETE | /api/v1/system-emails/{slug} | lists:write |
| GET | /api/v1/system-pages | lists:read |
| GET | /api/v1/system-pages/{slug} | lists:read |
| PUT | /api/v1/system-pages/{slug} | lists:write |
| DELETE | /api/v1/system-pages/{slug} | lists:write |
Formularios de suscripción
Crea, cambia, duplica y elimina los formularios de suscripción de tus listas.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/forms | lists:read |
| POST | /api/v1/forms | lists:write |
| GET | /api/v1/forms/{id} | lists:read |
| PUT, PATCH | /api/v1/forms/{id} | lists:write |
| DELETE | /api/v1/forms/{id} | lists:write |
| POST | /api/v1/forms/{id}/duplicate | lists:write |
Notificaciones
Crea notificaciones en el centro de notificaciones del titular de la cuenta: title (obligatorio), message, type (info, success, warning o error), list_id o action_url, y data de formato libre. No se envía nada a los suscriptores.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/notifications | cualquier clave válida |
| POST | /api/v1/notifications | notifications:write |
Endpoints auxiliares para integraciones
Endpoints que usan los plugins de WordPress, WooCommerce y otros: páginas externas, comprobación de versiones de plugins y conexiones. /api/webhooks/purchase recibe compras de integraciones de e-commerce y requiere una clave API válida.
| Método | Ruta | Scope |
|---|---|---|
| GET | /api/v1/external-pages | cualquier clave válida |
| GET | /api/v1/plugin/check-version | cualquier clave válida |
| POST | /api/v1/plugin/heartbeat | cualquier clave válida |
| GET | /api/v1/plugin/connections | cualquier clave válida |
| DELETE | /api/v1/plugin/connections/{id} | cualquier clave válida |
| POST | /api/v1/plugin/connections/{id}/disconnect | cualquier clave válida |
| POST | /api/webhooks/purchase | cualquier clave válida |
NetSendo Brain
El asistente de IA integrado en NetSendo: chat, conversaciones, base de conocimiento, planes de acción y su aprobación, ajustes y la conexión con Telegram. POST /brain/chat acepta un message de hasta 5.000 caracteres y un conversation_id opcional. El chat en modo manual forma parte de SILVER. Que Brain trabaje por su cuenta necesita GOLD: PUT /brain/settings responde 402 con work_mode semi_auto o autonomous, agent_modes no manuales, un telegram_bot_token o claves de investigación (perplexity_api_key, serpapi_api_key). Las entradas de la base de conocimiento admiten hasta 10.000 caracteres, 100.000 con GOLD; con GOLD, GET /brain/knowledge?search= también encuentra entradas por su significado (búsqueda semántica, desde 2.7.0).
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/brain/chat | cualquier clave válida |
| GET | /api/v1/brain/conversations | cualquier clave válida |
| GET | /api/v1/brain/conversations/{id} | cualquier clave válida |
| GET | /api/v1/brain/knowledge | cualquier clave válida |
| POST | /api/v1/brain/knowledge | cualquier clave válida |
| PUT | /api/v1/brain/knowledge/{id} | cualquier clave válida |
| DELETE | /api/v1/brain/knowledge/{id} | cualquier clave válida |
| GET | /api/v1/brain/plans | cualquier clave válida |
| GET | /api/v1/brain/plans/{id} | cualquier clave válida |
| POST | /api/v1/brain/plans/{id}/approve | cualquier clave válida |
| GET | /api/v1/brain/settings | cualquier clave válida |
| PUT | /api/v1/brain/settings | cualquier clave válida |
| POST | /api/v1/brain/telegram/link-code | cualquier clave válidaGOLD |
| POST | /api/v1/brain/telegram/disconnect | cualquier clave válida |
| POST | /api/v1/brain/telegram/test | cualquier clave válidaGOLD |
| POST | /api/v1/brain/telegram/set-webhook | cualquier clave válidaGOLD |
Endpoints de suscripción a listas
Para formularios web e integraciones sencillas que solo deben llegar a una lista. Estos endpoints no aceptan la clave API de la cuenta: autentícate con la clave propia de la lista, que se genera en los ajustes de la lista, en Integración → Clave API de la lista. subscribe acepta email (o phone en una lista SMS), first_name y last_name; unsubscribe acepta email. Una lista que no admite altas responde 403. Aquí los errores usan success: false con error o errors.
| Método | Ruta | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/subscribe | la clave API propia de la lista |
| POST | /api/v1/lists/{id}/unsubscribe | la clave API propia de la lista |
Ejemplos
curl -X POST https://your-domain.com/api/v1/subscribers \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "anna@example.com",
"contact_list_id": 5,
"first_name": "Anna",
"tags": [1, 3],
"custom_fields": { "city": "Berlin" }
}'
# 201 Created (200 when the address already existed)
{
"data": {
"id": 456,
"email": "anna@example.com",
"first_name": "Anna",
"status": "active",
"contact_list_id": 5,
"contact_list_ids": [5],
"source": "api",
"tags": [{ "id": 1, "name": "VIP", ... }, { "id": 3, "name": "Newsletter", ... }],
"custom_fields": { "email": "anna@example.com", "fname": "Anna", ..., "city": "Berlin" },
"subscribed_at": "2026-11-07T10:30:00.000000Z",
"created_at": "2026-11-07T10:30:00.000000Z",
...
}
}curl -X POST https://your-domain.com/api/v1/email/send \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "anna@example.com",
"subject": "Your order is on its way",
"content": "<p>Hi [[fname]], your order has shipped.</p>",
"subscriber_id": 456,
"mailbox_id": 1
}'
# 202 Accepted
{
"data": {
"id": 123,
"email": "anna@example.com",
"subject": "Your order is on its way",
"status": "queued",
"mailbox": "Main mailbox",
"scheduled_at": null
},
"message": "Email queued successfully"
}# 1. Create a draft email campaign for list 5
curl -X POST https://your-domain.com/api/v1/messages \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"subject": "November news",
"channel": "email",
"type": "broadcast",
"content": "<h1>Hello [[fname]]</h1>",
"contact_list_ids": [5],
"mailbox_id": 1
}'
# 2a. Send it now (42 = the id returned in step 1)
curl -X POST https://your-domain.com/api/v1/messages/42/send \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Accept: application/json"
# 2b. Or schedule it in a given time zone
curl -X POST https://your-domain.com/api/v1/messages/42/schedule \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "scheduled_at": "2026-11-20 09:00", "timezone": "Europe/Warsaw" }'const res = await fetch(
"https://your-domain.com/api/v1/subscribers?status=active&per_page=50",
{
headers: {
Authorization: `Bearer ${process.env.NETSENDO_API_KEY}`,
Accept: "application/json",
},
}
)
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") ?? 60)
// try again after `wait` seconds
}
const { data, meta } = await res.json()
console.log(meta.total, data.map((s) => s.email))curl -X POST https://your-domain.com/api/v1/lists/5/subscribe \
-H "Authorization: Bearer YOUR_LIST_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "email": "anna@example.com", "first_name": "Anna" }'
# 201 Created
{
"success": true,
"message": "Successfully subscribed",
"subscriber_id": 456,
"status": "new"
}Especificación OpenAPI en tu instancia
Cada instalación de NetSendo genera también una descripción OpenAPI de su API. Inicia sesión en el panel y abre https://your-domain.com/docs/api para la referencia interactiva, o /docs/api.json para la especificación sin procesar. Ambas solo son visibles para usuarios con sesión iniciada.

Preguntas frecuentes
¿Cómo me autentico en la API de NetSendo?
Crea una clave API en el panel de NetSendo, en Configuración → Claves API, y envíala en el encabezado Authorization como token Bearer: Authorization: Bearer ns_live_… La clave solo se muestra una vez, al crearla.
¿Cuál es el límite de solicitudes de la API de NetSendo?
3.000 solicitudes por minuto por clave API. Si se supera el límite, la API responde 429 Too Many Requests con un encabezado Retry-After. Los endpoints por lotes aceptan hasta 1.000 suscriptores por solicitud.
¿Qué scope necesita una clave para añadir suscriptores?
subscribers:write para POST /api/v1/subscribers y POST /api/v1/subscribers/batch. Las importaciones y los cambios masivos de membresía en una lista requieren lists:write. Un scope de escritura también concede el scope de lectura correspondiente.
¿Existe una especificación OpenAPI para la API de NetSendo?
Sí. Cada instalación genera una: inicia sesión en el panel y abre /docs/api para la referencia interactiva o /docs/api.json para la especificación.
¿Cómo puede un formulario web añadir suscriptores sin la clave API de la cuenta?
Genera una clave para la lista en sus ajustes, en Integración → Clave API de la lista, y envía los datos del formulario por POST a /api/v1/lists/{id}/subscribe con esa clave como token Bearer. La clave solo funciona para esa lista.
¿Qué diferencia hay entre /messages y /campaigns?
Ninguna. /campaigns es un alias de /messages: ambas rutas llevan a los mismos endpoints de campañas con los mismos scopes.

