Errores, límites e idempotencia
Cada error de la API de WhatSetter tiene la misma forma y un code estable. Esta página los lista todos, describe las cabeceras que reflejan tus límites y dice qué hacer cuando una llamada falla.
El sobre de error
Sección titulada «El sobre de error»{ "error": { "code": "insufficient_scope", "message": "This API key is missing the \"messages:send\" scope." }}codees estable: ramifica tu código con él.messagees para humanos y puede cambiar. Regístralo, no lo parsees.- El estado HTTP corresponde al código (mira la tabla). Las respuestas de éxito usan
{ "data": … }, y las listas añaden{ "pagination": { "has_more", "next_cursor" } }.
Códigos de error
Sección titulada «Códigos de error»| HTTP | code |
Cuándo ocurre | Qué hacer |
|---|---|---|---|
| 400 | validation_error |
La ruta contiene una codificación de URL inválida (por ejemplo %ZZ). |
Corrige la URL. |
| 401 | missing_api_key |
Ni cabecera Authorization: Bearer ni cabecera X-Api-Key. |
Envía la clave. |
| 401 | invalid_api_key |
La clave es desconocida, está revocada o no tiene el formato ws_live_. |
Revisa la clave, o crea una nueva. |
| 402 | plan_limit_reached |
POST /campaigns/{id}/resume cuando el cupo de campañas activas de tu plan está lleno. |
Pausa otra campaña, o cambia de plan. |
| 403 | insufficient_scope |
La clave no tiene el scope que este endpoint necesita. El mensaje lo nombra. | Crea una clave con ese scope. |
| 404 | not_found |
Ruta desconocida, o el recurso no existe, o pertenece a otro espacio. | Revisa el id y la ruta. |
| 409 | invalid_state |
Pausar una campaña que no está activa, reanudar una que no está en pausa, añadir un lead a una campaña que no está activa, o pasar a un humano un lead sin conversación. | Lee el mensaje y cambia el estado en el dashboard. |
| 409 | lead_not_contacted |
POST /messages a un lead al que nadie ha escrito todavía. |
El primer contacto pasa por una lista y una campaña. |
| 409 | request_in_flight |
Una petición con la misma Idempotency-Key todavía se está procesando. |
Espera unos segundos y reintenta con la misma clave. |
| 409 | already_blocked |
POST /blocked-contacts para un número o prefijo que ya está en la lista. |
Nada: ya está bloqueado. |
| 422 | validation_error |
Falta un parámetro o un campo del cuerpo, o es inválido: limit fuera de 1 a 100, una fecha que no es ISO 8601, un text vacío, un id de miembro desconocido en assigned_to. |
Corrige la petición. Reintentar tal cual volverá a fallar. |
| 429 | rate_limited |
Más peticiones por minuto de las que permite tu plan. | Espera Retry-After segundos y reintenta. |
| 429 | quota_exceeded |
Se alcanzó la cuota diaria de WhatsApp del número emisor (se reinicia a medianoche UTC), o un tope del espacio: 200 listas, 10 suscripciones de webhook, 500 contactos bloqueados. | Espera a X-Quota-Reset, o borra lo que no uses. |
| 500 | internal_error |
Un error inesperado de nuestro lado, o el backend de mensajería no está configurado. | Reintenta más tarde. Contacta con soporte si persiste. |
| 500 | server_error |
El control del agente no está configurado en este despliegue (handoff, resume). |
Contacta con soporte. |
| 502 | send_failed |
El motor de WhatsApp no confirmó el envío. | Reintenta con la misma Idempotency-Key. Sin clave, lee la conversación antes de volver a enviar. |
| 502 | upstream_error |
El workflow detrás de handoff, resume o POST /campaigns/{id}/leads rechazó la llamada o no estaba disponible. |
Reintenta en un momento. |
| 503 | agent_disconnected |
El número de WhatsApp de la campaña está desconectado, o no hay ningún número vinculado. | Reconecta el número en el dashboard. |
| 503 | service_unavailable |
El backend de autenticación no está disponible. | Reintenta en unos segundos. |
Cabeceras de límite de peticiones
Sección titulada «Cabeceras de límite de peticiones»Las peticiones se cuentan por espacio y por minuto, todas las claves juntas, con un límite fijado por tu plan (60 a 1000 por minuto, mira Autenticación y permisos). Cada respuesta lleva:
X-RateLimit-Limit: 300X-RateLimit-Remaining: 287X-RateLimit-Reset: 2026-09-19T10:01:00.000ZCuando se supera el límite, la respuesta es 429 rate_limited y añade Retry-After en segundos:
HTTP/1.1 429 Too Many RequestsRetry-After: 23Cabeceras de cuota
Sección titulada «Cabeceras de cuota»Enviar mensajes tiene un segundo presupuesto, separado: la cuota diaria del número de WhatsApp, la misma que usa el motor de campañas (mira la protección anti-ban). Un POST /messages con éxito la devuelve:
X-Quota-Limit: 150X-Quota-Remaining: 149X-Quota-Reset: 2026-09-20T00:00:00.000ZLos mismos números están en el cuerpo bajo data.quota (limit, used, remaining, resets_at). Cuando se alcanza la cuota recibes 429 quota_exceeded. Se reinicia a medianoche UTC. quota_exceeded también se usa para los topes del espacio listados en la tabla de arriba.
Idempotencia
Sección titulada «Idempotencia»POST /messages se puede reintentar sin riesgo cuando envías una cabecera Idempotency-Key: cualquier cadena única de 200 caracteres como máximo, por ejemplo un UUID por intención de envío.
curl -X POST https://app.whatsetter.com/api/v1/messages \ -H "Authorization: Bearer $WHATSETTER_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 4d3f9b2a-7c1e-4a8b-9f0d-2e6c8a1b3d5f" \ -d '{"lead_id":"66f1a2b3c4d5e6f7a8b9c0d1","text":"¿Confirmamos mañana a las 14h?"}'Qué hace la clave:
- Una clave que ya produjo una respuesta la repite con la cabecera
X-Idempotent-Replay: true. No se envía un segundo mensaje. - Un reintento lanzado mientras la primera petición sigue en curso recibe
409 request_in_flight. Espera unos segundos y reintenta con la misma clave. - Si un envío caduca o responde
502 send_failed, reintentar con la misma clave es seguro: WhatSetter repite el resultado registrado o responde409mientras se asienta. Nunca envía dos veces. - Las claves son propias de tu espacio y se recuerdan 15 minutos.
Cabecera de versión
Sección titulada «Cabecera de versión»Cada respuesta lleva X-Api-Version: 2026-07, la versión del contrato REST. Las cargas de los webhooks tienen su propio campo api_version (2026-06-01), descrito en la página de webhooks.
Consejos para reintentar
Sección titulada «Consejos para reintentar»| Respuesta | ¿Reintentar? | Cómo |
|---|---|---|
429 rate_limited |
Sí | Espera Retry-After segundos. |
429 quota_exceeded en POST /messages |
Sí, mañana | Espera a X-Quota-Reset (medianoche UTC). |
502 send_failed, 502 upstream_error, 503 * |
Sí | Backoff exponencial, empezando por unos segundos. Para POST /messages, reutiliza la misma Idempotency-Key. |
500 internal_error |
Una vez, más tarde | Si persiste, contacta con soporte con la ruta y la hora de la petición. |
409 request_in_flight |
Sí | Espera unos segundos, misma Idempotency-Key. |
Cualquier otro 4xx |
No | La petición en sí está mal. Corrígela primero. |

