Secciones: Fundamentos del API · Mensaje de texto · Plantilla con variables · Imagen y documento · Botones interactivos · Ubicación · Envío masivo con rate limiting · Manejo de errores y reintentos · Wrappers de clase completos (Node / Python / PHP)
Fundamentos del API: el único endpoint por el que pasa todo
Cada mensaje saliente de WhatsApp — sin importar el tipo — pasa por un único endpoint HTTP POST. El tipo de mensaje y el contenido están en el body JSON. Eso es todo. Sin WebSockets, sin streaming, sin long-polling.
API Endpoint
POST https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages
Authorization: Bearer {ACCESS_TOKEN}
Content-Type: application/json
// PHONE_NUMBER_ID — ID numérico de tu número de WhatsApp (NO el número de teléfono en sí)// Encuéntralo: Meta Developer Dashboard → WhatsApp → Phone Numbers// ACCESS_TOKEN — token permanente de System User// Encuéntralo: Meta Business Settings → System Users → Generate Token
Tres valores que necesitas antes de que se ejecute cualquier código:
Phone Number ID — un ID numérico para tu número de WhatsApp Business (se parece a 123456789012345). Distinto de tu número de teléfono real.
Access Token — un token permanente de System User con el permiso whatsapp_business_messaging. Nunca uses un token de usuario temporal en producción.
Número de teléfono del destinatario — en formato E.164: código de país + número, sin espacios, sin guiones, sin signo + en el valor JSON (p.ej. 15550001234 para un número de EE.UU., o con + también se acepta: +15550001234).
Un envío exitoso devuelve HTTP 200 con un body como:
Success Response
{
"messaging_product": "whatsapp",
"contacts": [{ "input": "+15550001234", "wa_id": "15550001234" }],
"messages": [{ "id": "wamid.HBgL..." }] // guárdalo para rastrear el estado de entrega
}
Tipos de mensaje: sesión vs plantilla
Antes de elegir un tipo de mensaje, necesitas saber si estás dentro de una ventana de servicio. La ventana de sesión (24 h después de que un cliente te escriba, o 72 h tras un clic en anuncio Click-to-WhatsApp) determina qué tipos de mensaje son gratuitos y sin restricciones.
💬
text
Texto plano. Soporta el formato similar a markdown de WhatsApp. Hasta 4.096 caracteres.
Gratis en ventana
📋
template
Formato pre-aprobado con huecos de variables. Necesario para iniciar contacto fuera de la ventana.
Requiere aprobación
🖼️
image
JPEG o PNG. Máx 5MB. URL o media ID. Caption opcional.
Gratis en ventana
📄
document
PDF, DOCX, XLSX. Máx 100MB. URL o media ID. Nombre de archivo visible.
Gratis en ventana
🎬
video
MP4 o 3GPP. Máx 16MB. URL o media ID. Caption opcional.
Gratis en ventana
🔘
interactive
Respuestas con botones (máx 3) o mensajes de lista (máx 10 ítems). El cliente toca para responder.
Gratis en ventana
📍
location
Envía lat/lng con nombre y dirección opcionales. Se renderiza como mapa en WhatsApp.
Gratis en ventana
🎵
audio
MP3 o AAC. Máx 16MB. URL o media ID. No soporta caption.
Gratis en ventana
Enviar un mensaje de texto
El envío más simple. Funciona dentro de la ventana de servicio de 24 horas sin cargo de Meta (dentro de la cuota mensual de 1.000 conversaciones de servicio gratuitas). Fuera de la ventana, usa una plantilla en su lugar.
Las plantillas son obligatorias para el primer mensaje de una conversación nueva, o cualquier mensaje enviado fuera de la ventana de servicio de 24 horas. Las plantillas se definen en WhatsApp Manager, las aprueba Meta, y pueden incluir marcadores de variables {{1}}{{2}}. Tu llamada al API rellena esas variables en el momento del envío.
Tiempo de aprobación de plantillas: Las plantillas utility simples (confirmaciones de pedido, actualizaciones de envío) suelen aprobarse en 1–24 horas. Las plantillas de marketing tardan 1–5 días hábiles. Puedes comprobar el estado de aprobación vía la suscripción webhook message_template_status_update o en WhatsApp Manager. Las plantillas en estado rechazado no se pueden enviar — enviar una plantilla no-APPROVED devuelve un error 400.
Los mensajes de media referencian un archivo por URL (el archivo debe ser accesible públicamente vía HTTPS) o por Media ID (obtenido tras subir el archivo al endpoint de media de Meta). URL es más simple para la mayoría de casos — el Cloud API lo descarga y lo cachea. Los Media IDs son mejores para activos reutilizados con frecuencia, como imágenes de producto o PDFs con tu marca.
Los mensajes interactivos de botones permiten a los clientes responder con un toque en lugar de escribir. Máximo 3 botones por mensaje. Los títulos de botón están limitados a 20 caracteres. Cuando un cliente toca un botón, tu webhook recibe un mensaje de tipo interactive con el id del botón en msg.interactive.button_reply.id.
Los mensajes de ubicación se renderizan como un pin en un mapa dentro de WhatsApp con un nombre y una dirección opcionales debajo. Los clientes pueden tocar para abrirlo en su app de mapas. No se necesita URL ni media ID — solo coordenadas.
Request body (all languages)
{
"messaging_product": "whatsapp",
"to": "+15550001234",
"type": "location",
"location": {
"latitude": 40.712776,
"longitude": -74.005974,
"name": "SocialHook HQ", // opcional — se muestra encima de la dirección"address": "123 Main St, New York, NY"// opcional
}
}
Envío masivo: rate limits y el patrón correcto
La WhatsApp Cloud API permite 80 mensajes por segundo por número de teléfono por defecto. A ese ritmo, enviar 10.000 mensajes tarda unos 2 minutos. Sin rate limiting, un bucle ingenuo agota el límite casi inmediatamente y empiezas a recibir errores 429 a mitad de campaña. El patrón correcto: añadir un delay fijo entre envíos e implementar exponential backoff en los 429.
Guarda el wamid devuelto y escucha los webhooks de estado de entrega
400 Bad Request
JSON inválido, campo obligatorio faltante, plantilla no aprobada, número de variables de plantilla no coincide
Revisa el body de la respuesta de error — Meta devuelve un error.message detallado explicando el campo o restricción exacta que falló
401 Unauthorized
Token de acceso inválido o expirado; falta el header Authorization
Regenera un token permanente de System User. Nunca uses tokens de usuario temporales en producción — expiran tras 60 días
404 Not Found
Phone Number ID equivocado en la URL; número no registrado en Cloud API
Verifica el Phone Number ID en Meta Developer Dashboard → WhatsApp → Phone Numbers. Confirma que el número está registrado y verificado.
429 Too Many Requests
Superado el límite de 80 msg/s, o el rate limit de llamadas al API
Implementa exponential backoff con jitter. Añade 15–20ms de delay entre envíos en operaciones masivas. No reintentes inmediatamente.
460 (Meta interno)
El número del destinatario no está registrado en WhatsApp
El número no es usuario de WhatsApp. Quítalo de tu lista. No es un número entregable.
131026
Mensaje no entregable — restricciones en la cuenta de WhatsApp del destinatario
El destinatario puede haber bloqueado tu número o su cuenta está restringida. Registra y omite.
500 / 503
Caída de infraestructura de Meta o error temporal
Reintenta con exponential backoff. Revisa metastatus.com para incidentes activos. No reintentes más de 3 veces.
Clase de cliente WhatsApp completa (Node.js)
Las funciones anteriores empaquetadas en una clase reutilizable con lógica de retry incorporada, manejo de errores consistente y configuración basada en variables de entorno:
Enviar mensajes es solo la mitad del panorama. Cuando tu cliente responde, la WhatsApp Cloud API dispara un webhook a tu servidor — pero necesitas un endpoint HTTPS accesible públicamente para recibirlo, además de verificación de firma HMAC-SHA256, extracción de payload anidado y manejo de reintentos.
SocialHook se encarga de toda la capa de entrada. Conecta tu número de WhatsApp a SocialHook, pega la URL de tu servidor como destino, y cada respuesta de cliente llega como un evento JSON normalizado — verificado, extraído del envoltorio anidado de Meta y reenviado a tu endpoint en menos de 50ms. El mismo formato plano funciona también para Facebook Messenger e Instagram DMs.
La configuración completa: tu servidor usa el WhatsAppClient anterior para los envíos, SocialHook entrega los eventos entrantes a tu handler de webhook. Dos direcciones, una sola tarifa plana de 50 $/mes. Mira la guía completa de webhook de entrada o empieza con el quickstart de 5 minutos.
FAQ
Preguntas frecuentes
¿Cómo envío un mensaje de WhatsApp usando la Cloud API?
POST a https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages con tu header Authorization: Bearer {ACCESS_TOKEN} y un body JSON con messaging_product: "whatsapp", to: "+E.164_number", type: "text", y text: { body: "message" }. Código completo para Node.js, Python y PHP está en la sección de mensaje de texto arriba.
¿Qué es el Phone Number ID de WhatsApp y dónde lo encuentro?
El Phone Number ID es un identificador numérico para tu número específico de WhatsApp Business en la Cloud API — es distinto del número de teléfono real. Encuéntralo en Meta Developer Dashboard → WhatsApp → Phone Numbers. Tiene aspecto de 15–16 dígitos. Úsalo en la URL: graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages. Un número de teléfono tiene un ID que nunca cambia.
¿Cuál es la diferencia entre un mensaje de sesión y uno de plantilla?
Un mensaje de sesión (texto, imagen, botones, ubicación, documento) solo puede enviarse dentro de la ventana de servicio de 24 horas que se abre cuando un cliente te escribe primero. Estos son gratuitos dentro de la cuota mensual. Un mensaje de plantilla es un formato aprobado por Meta necesario para iniciar nuevas conversaciones o enviar fuera de la ventana de servicio. Las plantillas deben aprobarse (1–24 h para utility, hasta 5 días para marketing) antes de poder enviarse.
¿Qué pasa cuando recibo un 429 de la WhatsApp Cloud API?
Has alcanzado el rate limit (80 msg/s por defecto). Implementa exponential backoff: espera 1000 * 2^attempt + random(500) ms antes de reintentar, con tope de 60 segundos. Añade jitter (el componente aleatorio) para evitar reintentos sincronizados desde múltiples workers. Para campañas masivas, añade un delay fijo de 15–20ms entre envíos para mantenerte con seguridad bajo el límite en vez de alcanzarlo y reintentar.
¿Cómo envío una plantilla de WhatsApp con variables en Python?
Pon "type": "template" e incluye un array components con un componente body que contenga parameters — un objeto por cada variable en tu plantilla. Cada parámetro es {"type": "text", "text": "variable_value"}. Se mapean secuencialmente a {{1}}, {{2}}, {{3}} en tu plantilla. El código Python completo está en la sección de mensaje de plantilla arriba.
¿Cómo recibo las respuestas de los clientes a mensajes de WhatsApp?
Las respuestas de clientes llegan vía webhook — Meta dispara un HTTP POST a tu endpoint registrado cuando ocurre cualquier evento de mensaje. Necesitas una URL HTTPS accesible públicamente, verificación de firma HMAC-SHA256 y parseo de payload anidado. SocialHook se encarga de todo esto automáticamente y entrega JSON limpio a tu endpoint en menos de 50ms. Mira la configuración completa en nuestra guía de webhook de entrada.
Tu código de salida está listo. Conecta SocialHook para la entrada — cada respuesta de cliente llega como JSON limpio a tu endpoint de webhook. Sin código boilerplate de HMAC, sin parseo de payload anidado, sin infraestructura de reintentos que construir.