Ir al contenido

Mensajes

POST /messages escribe a un lead desde el número de WhatsApp de su campaña, como si un compañero hubiera tomado el control en el dashboard. Las reglas anti-ban se aplican en el servidor y no se pueden saltar.

Método Ruta Scope
POST /messages messages:send
Terminal window
curl -X POST "https://app.whatsetter.com/api/v1/messages" \
-H "Authorization: Bearer ws_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8c3d2f9e-7b1a-4e6f-9c0d-2a1b3c4d5e6f" \
-d '{"lead_id":"66f1a2b3c4d5e6f7a8b9c0d1","text":"¿Confirmamos mañana a las 14h?"}'
{
"data": {
"id": "66f1a2b3c4d5e6f7a8b9c0e5",
"message_id": "true_34612345678@c.us_3EB0C8F2A1D4B5E6F7A8",
"lead_id": "66f1a2b3c4d5e6f7a8b9c0d1",
"text": "¿Confirmamos mañana a las 14h?",
"sent_at": "2026-09-19T08:12:04.000Z",
"humanized": true,
"typing_ms": 3210,
"quota": {
"limit": 250,
"used": 41,
"remaining": 209,
"resets_at": "2026-09-20T00:00:00.000Z"
}
}
}
Campo Significado
id El id de la fila de conversación en WhatSetter, o null si la fila no se pudo escribir tras el envío.
message_id El id del mensaje de WhatsApp.
lead_id El lead al que escribiste.
text El texto enviado.
sent_at Cuándo lo aceptó el motor.
humanized Si se reprodujo la coreografía humana.
typing_ms El retraso de escritura simulado, 0 cuando humanize es false.
quota El presupuesto diario del número tras este envío.

201 significa que el motor de WhatsApp aceptó el mensaje. La entrega final es asíncrona, como en cualquier API de WhatsApp. El mensaje aparece en la conversación del dashboard como una respuesta manual.

El lead ya debe tener una conversación: al menos un mensaje intercambiado. Si no, recibes 409 lead_not_contacted. El primer contacto pasa por una lista y una campaña o por un lead opt-in.

Cada envío consume el mismo presupuesto diario que el motor de campaña para ese número de WhatsApp (250 mensajes al día cuando no hay una cuota específica configurada). Al alcanzarlo: 429 quota_exceeded, se reinicia a medianoche UTC.

Cada 201 y cada 429 llevan el presupuesto en las cabeceras:

X-Quota-Limit: 250
X-Quota-Remaining: 209
X-Quota-Reset: 2026-09-20T00:00:00.000Z

Si la campaña no tiene número de WhatsApp, o el número está desconectado, recibes 503 agent_disconnected. Comprueba whatsapp_connected en GET /campaigns y reconéctalo desde el dashboard.

Por defecto (humanize: true), el envío reproduce una coreografía humana: confirmación de lectura, indicador «escribiendo», un retraso de escritura proporcional a la longitud del mensaje, y después el envío. Cuenta con 3 a 15 segundos por petición. Es el modo recomendado.

"humanize": false envía al instante, siempre bajo cuota. Resérvalo para confirmaciones urgentes.

text es obligatorio, de 1 a 4096 caracteres, solo texto.

Una API de mensajes debe poder reintentarse sin peligro: un timeout nunca debe convertirse en un segundo mensaje real de WhatsApp. Pasa una cabecera Idempotency-Key en cada envío, única por intención (un UUID, un id de pedido…), hasta 200 caracteres. WhatSetter la recuerda 15 minutos.

Situación Qué obtiene un reintento con la misma clave
La primera llamada respondió 201 El mismo cuerpo 201, con la cabecera X-Idempotent-Replay: true. Sin segundo mensaje.
La primera llamada sigue en curso 409 request_in_flight. Espera y reintenta.
La primera llamada falló limpiamente (422, 409, 429, 503) La clave se libera: tu reintento es un intento nuevo de verdad.
La primera llamada caducó (502 send_failed) 409 request_in_flight hasta el final de la ventana: puede que el mensaje haya salido. Comprueba la transcripción antes de volver a enviar.
HTTP code Cuándo
401 missing_api_key, invalid_api_key Clave ausente, desconocida o revocada.
403 insufficient_scope La clave no tiene messages:send.
404 not_found Lead desconocido, o lead de otro espacio de trabajo.
409 lead_not_contacted El lead nunca fue contactado. Pasa por una lista o un lead opt-in.
409 request_in_flight La misma Idempotency-Key sigue procesándose, o un intento anterior con ella caducó.
422 validation_error lead_id ausente, text vacío o demasiado largo, humanize que no es booleano, clave de más de 200 caracteres.
429 quota_exceeded Presupuesto diario del número alcanzado. Ver X-Quota-Reset.
429 rate_limited Demasiadas peticiones este minuto. Respeta Retry-After.
500 internal_error Motor de mensajería no configurado por nuestra parte.
502 send_failed El motor rechazó o no confirmó el envío. Reintenta con la misma clave.
503 agent_disconnected Sin número en la campaña, o número desconectado.