Listas e importación
Una lista es un lote de contactos destinado a una campaña. Es la única puerta para la prospección en frío: los contactos pasan por la verificación y el envío pausado anti-ban de WhatSetter, nunca por un envío directo.
Endpoints
Sección titulada «Endpoints»| Método | Ruta | Scope |
|---|---|---|
| GET | /lists |
lists:read |
| POST | /lists |
lists:write |
| POST | /lists/{id}/leads |
lists:write |
Crear una lista
Sección titulada «Crear una lista»curl -X POST "https://app.whatsetter.com/api/v1/lists" \ -H "Authorization: Bearer ws_live_…" \ -H "Content-Type: application/json" \ -d '{"name":"Sync CRM, leads calientes"}'const res = await fetch('https://app.whatsetter.com/api/v1/lists', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Sync CRM, leads calientes' }),});const { data: list } = await res.json();import requests
r = requests.post( "https://app.whatsetter.com/api/v1/lists", headers={"Authorization": "Bearer ws_live_…"}, json={"name": "Sync CRM, leads calientes"},)lst = r.json()["data"]{ "data": { "id": "66f1a2b3c4d5e6f7a8b9c0a1", "name": "Sync CRM, leads calientes", "status": "ready", "total_rows": 0, "valid_leads": 0, "invalid_leads": 0, "created_at": "2026-09-19T08:00:00.000Z" }}name tiene de 1 a 255 caracteres. Un espacio de trabajo admite hasta 200 listas; más allá, 429 quota_exceeded.
Importar leads
Sección titulada «Importar leads»Hasta 500 leads por llamada. Cada lead necesita un phone en formato internacional. name, email y custom_variables son opcionales.
curl -X POST "https://app.whatsetter.com/api/v1/lists/66f1a2b3c4d5e6f7a8b9c0a1/leads" \ -H "Authorization: Bearer ws_live_…" \ -H "Content-Type: application/json" \ -d '{ "leads": [ { "phone": "+34612345678", "name": "Julien", "email": "julien@example.com", "custom_variables": { "ciudad": "Madrid", "plan": "Pro" } }, { "phone": "+34698765432", "name": "María" } ] }'const res = await fetch('https://app.whatsetter.com/api/v1/lists/66f1a2b3c4d5e6f7a8b9c0a1/leads', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…', 'Content-Type': 'application/json' }, body: JSON.stringify({ leads: [ { phone: '+34612345678', name: 'Julien', email: 'julien@example.com', custom_variables: { ciudad: 'Madrid', plan: 'Pro' } }, { phone: '+34698765432', name: 'María' }, ], }),});const { data: result } = await res.json();import requests
r = requests.post( "https://app.whatsetter.com/api/v1/lists/66f1a2b3c4d5e6f7a8b9c0a1/leads", headers={"Authorization": "Bearer ws_live_…"}, json={ "leads": [ {"phone": "+34612345678", "name": "Julien", "email": "julien@example.com", "custom_variables": {"ciudad": "Madrid", "plan": "Pro"}}, {"phone": "+34698765432", "name": "María"}, ] },)result = r.json()["data"]{ "data": { "imported": 2, "duplicates_in_list": 0, "rejected": [], "lead_ids": ["66f1a2b3c4d5e6f7a8b9c0b1", "66f1a2b3c4d5e6f7a8b9c0b2"] }}El estado es 201 en cuanto al menos un lead era importable. lead_ids son las filas importadas, en el orden de creación. name y email se recortan a 255 caracteres.
Deduplicación y rechazos
Sección titulada «Deduplicación y rechazos»| Caso | Qué pasa |
|---|---|
| El mismo número dos veces en el lote | Se conserva el primero, el otro aparece en rejected con la razón duplicate_in_batch. |
| Número ya presente en esta lista | No se vuelve a crear, se cuenta en duplicates_in_list. |
| Número inválido | En rejected con una razón que empieza por invalid_phone. Un número válido tiene de 8 a 15 dígitos, con o sin +, espacios, puntos, guiones o paréntesis. |
custom_variables no es un objeto |
Rechazado con la razón custom_variables must be an object. |
custom_variables supera 2000 caracteres una vez serializado |
Rechazado con la razón custom_variables exceeds 2000 characters. |
Las entradas de rejected llevan el index del lead en tu array, para registrar o reintentar con precisión.
Las columnas personalizadas se convierten en variables
Sección titulada «Las columnas personalizadas se convierten en variables»Cada clave de custom_variables se convierte en una variable por lead que tu agente puede usar en su primer mensaje, escrita {{lead:clave}} en el editor de prompt. Las claves se normalizan a un slug: sin acentos, en minúsculas, y todo lo que no sea letra o dígito pasa a _. Ciudad del cliente y ciudad_del_cliente son la misma variable.
Con el ejemplo de arriba, el prompt puede decir {{lead:ciudad}} y {{lead:plan}}. Una clave ausente en un lead concreto se le indica al agente como no proporcionada, con la instrucción de no inventar nunca un valor.
Paginación
Sección titulada «Paginación»GET /lists devuelve las 100 listas más recientes del espacio de trabajo, en data, las más recientes primero. No hay cursor en este endpoint.
{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c0a1", "name": "Sync CRM, leads calientes", "status": "ready", "total_rows": 2, "valid_leads": 0, "invalid_leads": 0, "created_at": "2026-09-19T08:00:00.000Z" } ]}valid_leads e invalid_leads se van rellenando a medida que WhatSetter verifica los números tras la importación.
Cómo una lista alimenta una campaña
Sección titulada «Cómo una lista alimenta una campaña»Importar no envía nada. La lista la recoge la campaña a la que está vinculada en el dashboard: las filas se verifican y después se envían a un ritmo humano, dentro de la cuota diaria del número. Vincula la lista desde tu campaña en el dashboard y luego sigue los leads con GET /leads?campaign_id=.
Leads opt-in: la otra puerta
Sección titulada «Leads opt-in: la otra puerta»Cuando una persona acaba de apuntarse en tu embudo y espera un mensaje ahora, usa POST /campaigns/{id}/leads en su lugar. Envía de inmediato un primer mensaje personalizado, con las mismas protecciones anti-ban, y te deja adjuntar un external_reference.
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. |
| 403 | insufficient_scope |
La clave no tiene lists:read o lists:write. |
| 404 | not_found |
Lista desconocida, o lista de otro espacio de trabajo. |
| 422 | validation_error |
name ausente o demasiado largo; leads que no es un array de 1 a 500; ningún lead importable en el lote (el mensaje da la primera razón). |
| 429 | quota_exceeded |
Ya existen 200 listas en el espacio de trabajo. |
| 429 | rate_limited |
Demasiadas peticiones este minuto. Respeta Retry-After. |

