Campañas
Una campaña es un agente IA, un número de WhatsApp y una audiencia. La API te da el directorio (ids, estado, estado de conexión), el interruptor de pausa y reanudación, y la puerta para los leads opt-in.
Endpoints
Sección titulada «Endpoints»| Método | Ruta | Scope |
|---|---|---|
| GET | /campaigns |
campaigns:read |
| POST | /campaigns/{id}/pause |
campaigns:write |
| POST | /campaigns/{id}/resume |
campaigns:write |
| POST | /campaigns/{id}/leads |
messages:send |
Listar campañas
Sección titulada «Listar campañas»curl "https://app.whatsetter.com/api/v1/campaigns" \ -H "Authorization: Bearer ws_live_…"const res = await fetch('https://app.whatsetter.com/api/v1/campaigns', { headers: { Authorization: 'Bearer ws_live_…' },});const { data: campaigns } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/campaigns", headers={"Authorization": "Bearer ws_live_…"},)campaigns = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c0c1", "campaign_id": "acme-espana-1-ab12", "name": "Alex", "status": "active", "purpose": "setter", "whatsapp_connected": true, "created_at": "2026-08-01T09:00:00.000Z" } ]}| Campo | Significado |
|---|---|
id |
El id del documento de campaña. Se acepta en todas las rutas /campaigns/{id}/.... |
campaign_id |
El slug que los leads, conversaciones y reservas llevan en su propio campaign_id. También se acepta en rutas y filtros. |
name |
El nombre visible del agente. |
status |
active, draft, paused, archived, o unknown para un valor interno. |
purpose |
setter (conversaciones 1 a 1) o group (grupos de WhatsApp). |
whatsapp_connected |
true cuando el número de la campaña puede enviar ahora mismo. |
La lista contiene hasta 100 campañas, las más recientes primero. No hay cursor.
Pausar y reanudar
Sección titulada «Pausar y reanudar»Pausar detiene las respuestas de la IA y los envíos, igual que el interruptor del dashboard. Reanudar los reactiva.
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/pause" \ -H "Authorization: Bearer ws_live_…"const res = await fetch('https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/pause', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…' },});const { data: campaign } = await res.json();import requests
r = requests.post( "https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/pause", headers={"Authorization": "Bearer ws_live_…"},)campaign = r.json()["data"]La respuesta es el objeto campaña con su nuevo status. Solo existen dos transiciones:
| Llamada | Permitida desde | Resultado | Si no |
|---|---|---|---|
POST /campaigns/{id}/pause |
active |
paused |
409 invalid_state |
POST /campaigns/{id}/resume |
paused |
active |
409 invalid_state |
Una campaña draft debe activarse desde el dashboard. Una campaña archived no se puede reanudar.
Reanudar depende del límite de campañas activas de tu plan: Free y Starter 1, Business 3, Scale 10, más los agentes adicionales añadidos a tu plan. Cuando el límite está lleno, reanudar responde 402 plan_limit_reached: pausa otra campaña o cambia de plan.
Empujar un lead opt-in
Sección titulada «Empujar un lead opt-in»Cuando alguien se apunta en tu embudo o tu CRM, empújalo a la campaña. WhatSetter ejecuta el mismo flujo que el webhook de página de venta de la campaña: validación del teléfono y comprobación de WhatsApp, deduplicación contra los contactos ya contactados, cuota diaria de primeros contactos, y después un primer mensaje escrito por la IA a partir de la plantilla de la campaña, el nombre del lead y cada clave de additional_data.
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/leads" \ -H "Authorization: Bearer ws_live_…" \ -H "Content-Type: application/json" \ -d '{ "phone": "+34612345678", "name": "Julien", "email": "julien@example.com", "source_url": "crm:hubspot", "external_reference": "4471", "additional_data": { "oferta": "Pack Pro", "ciudad": "Madrid", "presupuesto": "500-1000" } }'const res = await fetch('https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/leads', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…', 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: '+34612345678', name: 'Julien', email: 'julien@example.com', source_url: 'crm:hubspot', external_reference: '4471', additional_data: { oferta: 'Pack Pro', ciudad: 'Madrid', presupuesto: '500-1000' }, }),});const { data } = await res.json(); // 202import requests
r = requests.post( "https://app.whatsetter.com/api/v1/campaigns/acme-espana-1-ab12/leads", headers={"Authorization": "Bearer ws_live_…"}, json={ "phone": "+34612345678", "name": "Julien", "email": "julien@example.com", "source_url": "crm:hubspot", "external_reference": "4471", "additional_data": {"oferta": "Pack Pro", "ciudad": "Madrid", "presupuesto": "500-1000"}, },)data = r.json()["data"] # 202{ "data": { "status": "accepted", "campaign_id": "acme-espana-1-ab12", "phone": "+34612345678", "external_reference": "4471", "note": "Queued into the first-contact pipeline: deduplication, daily first-contact quota and anti-ban pacing apply. The lead is created later, so no lead id exists yet…" }}| Campo | Reglas |
|---|---|
phone |
Obligatorio. Formato internacional, de 6 a 15 dígitos. Se devuelve con un +. |
name, email |
Opcionales, recortados a 255 caracteres. |
source_url |
Opcional, hasta 255 caracteres. De dónde viene el lead. Por defecto api. |
external_reference |
Opcional, hasta 255 caracteres. El identificador de tu propia ficha, guardado tal cual y devuelto en cada lead y cada webhook. |
additional_data |
Objeto opcional, hasta 30 claves y 2000 caracteres una vez serializado. Sirve para personalizar el primer mensaje, nunca se guarda, nunca se devuelve. Las claves con el nombre de los campos de arriba (phone, name, email, source_url, external_reference) se ignoran. |
Es asíncrono
Sección titulada «Es asíncrono»El endpoint responde 202 en cuanto el lead se acepta. La fila del lead se crea más tarde, tras la deduplicación y el ritmo de envío, así que todavía no hay id de lead. Para hacer seguimiento:
- busca el lead con
GET /leads?external_reference=4471(o?phone=+34612345678); - o suscríbete a los webhooks:
contact.external_referencelleva tu identificador.
Un contacto ya contactado por la campaña se deduplica en silencio: sin segundo primer mensaje, y el 202 es idéntico. Los leads que superan la cuota se ponen en cola para la siguiente ventana, nunca se pierden.
Dos presupuestos protegen el número, y la API no puede saltarse ninguno:
- Primeros contactos diarios por campaña: los leads opt-in que lo superan esperan al día siguiente.
- Mensajes diarios por número de WhatsApp: compartidos con
POST /messages, ver Mensajes para las cabecerasX-Quota-*.
Además, las peticiones se limitan por espacio de trabajo y por minuto según el plan (429 rate_limited con Retry-After).
Errores que encontrarás
Sección titulada «Errores que encontrarás»| HTTP | code |
Cuándo |
|---|---|---|
| 401 | missing_api_key, invalid_api_key |
Clave ausente, desconocida o revocada. |
| 402 | plan_limit_reached |
Reanudación rechazada: el límite de campañas activas del plan está lleno. |
| 403 | insufficient_scope |
La clave no tiene campaigns:read, campaigns:write o messages:send. |
| 404 | not_found |
Campaña desconocida, o campaña de otro espacio de trabajo. |
| 409 | invalid_state |
Pausa sobre una campaña no activa, reanudación sobre una no pausada, lead empujado a una campaña no activa, o campaña nunca abierta en el dashboard. |
| 422 | validation_error |
Teléfono inválido, additional_data que no es un objeto o demasiado grande, external_reference demasiado largo. |
| 429 | rate_limited |
Demasiadas peticiones este minuto. Respeta Retry-After. |
| 502 | upstream_error |
El flujo de primer mensaje no estaba disponible. Reintenta en un momento. |

