Forma de la respuesta
{ "message_uuid": "...", "wamid": "..." }
{
"code": "WINDOW_CLOSED",
"message": "The 24-hour messaging window is closed. Send an approved template to reopen it."
}
{ code, message } — ambos campos están garantizados.
Haz
switch sobre code: es estable y forma parte del contrato. El
message es texto humano de ayuda y puede afinarse entre versiones de la
API sin aviso. Los mensajes se entregan en inglés (estándar de industria,
mismo patrón que Stripe, GitHub o Linear). Si necesitas mostrarlos
traducidos al usuario final, mapéalos en tu cliente por code.Familias de status
| HTTP | Significado | ¿Reintentar? |
|---|---|---|
2xx | Éxito — 200 lectura, 201 creación, 202 aceptado (async), 207 multi-status. | — |
4xx | Error del request — auth, validación o recurso inexistente. | No, corrígelo primero. |
429 | Rate limit excedido. | Sí, tras el Retry-After. |
5xx | Error del servidor. | Sí, con backoff. |
Catálogo de códigos
El status HTTP de cada código es típico: el endpoint puntual puede devolver
otro status si el contexto lo justifica. El authoritative por endpoint vive en
la sección Referencia de API. La tabla aquí es referencia general, no
contrato vinculante por endpoint.Los códigos de ambigüedad de resolución de conversación (
PHONE_NUMBER_AMBIGUOUS,
USERNAME_AMBIGUOUS) pueden aparecer en cualquier endpoint que acepte una
referencia conversation por phone/username, aunque su Referencia de API
liste otros códigos 409.Auth y tenant
| Code | HTTP | Descripción |
|---|---|---|
INVALID_API_TOKEN | 401 | El token no existe o fue revocado. Genera uno nuevo en Settings → API Token. |
TOKEN_BUSINESS_MISMATCH | 403 | El token no pertenece al slug del negocio en la URL. Verifica que ambos refieran al mismo negocio. |
Rate limit
| Code | HTTP | Descripción |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Superaste el bucket de 60 req/min. Espera los segundos del header Retry-After. Ver Rate limits. |
Validación
| Code | HTTP | Descripción |
|---|---|---|
INVALID_REQUEST | 400 | El body no pasó la validación de schema (campo faltante, tipo incorrecto, valor fuera de rango). |
INVALID_CURSOR | 400 | El cursor de paginación es inválido o expiró. Reinicia el listado sin cursor. |
BATCH_LIMIT_EXCEEDED | 400 | El grupo de acciones excede el máximo permitido en una sola request. El message lleva el cap real. |
Conversación, contacto y canal
| Code | HTTP | Descripción |
|---|---|---|
CONVERSATION_NOT_FOUND | 404 | El identificador de conversation (uuid, whatsapp_user_id, username o phone) no resuelve a ninguna conversación del negocio. |
CONTACT_NOT_FOUND | 404 | El identificador de contacto no resuelve a ninguno del negocio. |
PHONE_NUMBER_AMBIGUOUS | 409 | Varios contactos comparten ese teléfono (números reciclados / identidades separadas). Identifica la conversación por whatsapp_user_id o uuid. |
USERNAME_AMBIGUOUS | 409 | Varios contactos comparten ese username. Identifica la conversación por whatsapp_user_id o uuid. |
CHANNEL_NOT_CONFIGURED | 422 | La conversación no tiene un canal de WhatsApp configurado. Conecta uno en el dashboard antes de enviar. |
TESTER_CONVERSATION_NOT_WRITABLE | 422 | Las conversaciones tester no aceptan envíos reales a WhatsApp. Usa una real, o limita la acción a tags/notas/mailbox. |
TRANSCRIPTION_REQUIRED_TO_RESOLVE | 422 | POST /conversation/resolve: la conversación tiene media entrante con transcripción pendiente. Completa la transcripción manual desde el dashboard y reintenta. |
Tags
| Code | HTTP | Descripción |
|---|---|---|
TAG_NOT_FOUND | 404 | El tag no existe para este negocio. |
TAG_ALREADY_ASSIGNED | 409 | El tag ya está asignado a esta conversación. |
TAG_NOT_ASSIGNED | 404 | El tag no está asignado, por lo que no se puede remover. |
TAG_AMBIGUOUS | 409 | Hay varios tags con ese nombre. Usa tag_uuid para desambiguar. |
TAG_BUSINESS_MISMATCH | 400 | El tag pertenece a otro negocio. |
CANNOT_ASSIGN_DEFAULT_TAG | 422 | El tag es de sistema (lo administra el backend, ej. el de conversión pendiente) y no puede asignarse por API. |
CANNOT_REMOVE_DEFAULT_TAG | 422 | El tag es de sistema (lo administra el backend, ej. el de conversión pendiente) y no puede removerse por API. |
Mailboxes y categorías
| Code | HTTP | Descripción |
|---|---|---|
CATEGORY_NOT_FOUND | 404 | La categoría de mailbox no existe para este negocio. |
CATEGORY_BUSINESS_MISMATCH | 403 | La categoría pertenece a otro negocio. |
AMBIGUOUS_CATEGORY | 409 | Hay varias categorías con ese nombre. Usa category_uuid para desambiguar. |
MAILBOX_NOT_FOUND | 404 | El mailbox no existe para este negocio. |
MAILBOX_ALREADY_ASSIGNED | 409 | La conversación ya está en ese mailbox. |
AMBIGUOUS_MAILBOX | 409 | Hay varios mailboxes con ese nombre. Usa mailbox_uuid para desambiguar. |
NO_MAILBOXES_IN_CATEGORY | 422 | La categoría no tiene mailboxes configurados. Agrega al menos uno en el dashboard. |
Guards de precondición
| Code | HTTP | Descripción |
|---|---|---|
WINDOW_CLOSED | 422 | La ventana de 24h está cerrada. Envía una plantilla aprobada para reabrirla. |
WALLET_BLOCKED | 402 | El wallet de tokens del modelo AI requerido está vacío o bloqueado. Recarga para continuar. |
VISION_WALLET_BLOCKED | 402 | El wallet de vision tokens está vacío. El procesamiento de visión requiere recarga. |
VISION_BLOCKED | 402 | El pipeline de visión del thread está bloqueado. Resuelve la media pendiente en el dashboard antes de reintentar. |
NO_AI_EMPLOYEE_ASSIGNED | 422 | La conversación no tiene un empleado AI asignado. Asigna uno antes de ejecutar la acción. |
Coherencia owner ↔ executor (schedules)
| Code | HTTP | Descripción |
|---|---|---|
OWNER_MISMATCH | 422 | El executor del scheduled message no coincide con el owner actual de la conversación. Reasigna o cancela el schedule primero. |
Empleados AI y ejecución
| Code | HTTP | Descripción |
|---|---|---|
AI_EMPLOYEE_NOT_FOUND | 404 | El empleado AI no existe para este negocio. |
AMBIGUOUS_AI_EMPLOYEE | 409 | Hay varios empleados con ese nombre. Usa ai_employee_uuid para desambiguar. |
AI_EMPLOYEE_ALREADY_ASSIGNED | 409 | Ese empleado AI ya está asignado a la conversación. |
INVALID_ASSIGNEE_FOR_RUN_AI | 409 | La conversación es human-owned y no se pasó ai_employee. Especifica uno o reasigna un AI primero. |
AI_EXECUTION_FAILED | 500 | La ejecución del AI falló inesperadamente. Reintenta; si persiste, revisa el dashboard del empleado. |
ACTIONS_DEPTH_EXCEEDED | 422 | Las acciones AI encadenadas exceden la profundidad máxima permitida en una request. |
Scheduled message action
| Code | HTTP | Descripción |
|---|---|---|
SCHEDULED_MESSAGE_ACTION_REQUIRED | 422 | Hay un scheduled message activo en la conversación. Especifica scheduled_message_action (reassign o cancel). |
SCHEDULED_MESSAGE_ACTION_INVALID | 400 | El valor de scheduled_message_action es inválido. Debe ser reassign o cancel. |
Uploads
| Code | HTTP | Descripción |
|---|---|---|
INVALID_FILE_TYPE | 400 | El tipo de archivo no está permitido. Ver la documentación para la lista de MIME types aceptados. |
FILE_TOO_LARGE | 400 | El archivo excede el tamaño máximo para su categoría. |
STORAGE_QUOTA_EXCEEDED | 413 | El negocio alcanzó su cuota de storage. Libera espacio o sube de plan. |
STORAGE_QUOTA_CLEANUP_INSUFFICIENT | 507 | El storage está lleno y la limpieza automática no pudo liberar suficiente espacio para este upload. Libera espacio o sube de plan. |
FILE_NOT_FOUND | 404 | No existe un archivo con ese file_uuid para este negocio. |
FILE_NOT_UPLOADED | 422 | El archivo fue registrado pero el upload nunca se confirmó. Re-súbelo antes de referenciarlo. |
SIZE_MISMATCH | 422 | El tamaño real del archivo subido no coincide con el declarado en request-upload. |
MIME_MISMATCH | 422 | El MIME type real no coincide con el declarado. Re-sube con el Content-Type correcto. |
UPLOAD_FAILED | 500 | El upload no se pudo completar por un error de storage. Reintenta. |
Mensajes
| Code | HTTP | Descripción |
|---|---|---|
PREPARE_FAILED | 500 | El mensaje no se pudo preparar (error de DB o upstream). Reintenta. |
SEND_FAILED | 502 | El envío a WhatsApp falló. Verifica la salud del canal y reintenta. |
BSUID_SEND_DISABLED | 409 | El contacto no tiene teléfono y el envío por su identidad BSUID (business-scoped user ID) está deshabilitado para este negocio. Usa un contacto con teléfono o habilita el envío por BSUID. |
Quick replies y plantillas
| Code | HTTP | Descripción |
|---|---|---|
QUICK_REPLY_NOT_FOUND | 404 | La quick reply no existe para este negocio. |
QUICK_REPLY_AMBIGUOUS | 409 | Hay varias quick replies con ese nombre. Usa quick_reply_uuid para desambiguar. |
QUICK_REPLY_EMPTY | 422 | La quick reply no tiene acciones configuradas. Agrega al menos una en el dashboard. |
TEMPLATE_NOT_FOUND | 404 | La plantilla no existe para este negocio. |
TEMPLATE_NOT_APPROVED | 422 | La plantilla no está aprobada por Meta. La aprobación es requisito para enviar. |
AUTH_TEMPLATE_REQUIRES_PHONE | 409 | No se puede enviar una plantilla de autenticación a un contacto sin teléfono: Meta exige el número. Envía a un contacto con teléfono. |
TEMPLATE_AMBIGUOUS | 409 | Hay varias plantillas con ese nombre. Especifica language para desambiguar. |
TEMPLATE_VARIABLES_INVALID | 422 | Las variables del body no coinciden con la plantilla (conteo incorrecto, índice faltante o valor vacío). |
TEMPLATE_HEADER_MISMATCH | 400 | El tipo de header no coincide con el que declara la plantilla (ej: la plantilla espera imagen y enviaste texto). |
TEMPLATE_FAKE_REQUIRES_TESTER_CONVERSATION | 422 | La plantilla es del módulo Tester (fake) y solo puede enviarse a conversaciones tester. |
Operaciones genéricas
| Code | HTTP | Descripción |
|---|---|---|
FETCH_FAILED | 500 | No se pudieron leer los datos necesarios para completar el request. Reintenta. |
UPDATE_FAILED | 500 | El cambio no se pudo aplicar (error de DB). Reintenta. |
UNKNOWN_ERROR | 500 | Error inesperado. Contacta a soporte si persiste. |