Ir al contenido

Enviar notificaciones por WhatsApp

Summit Notify envía mensajes de WhatsApp mediante AWS End User Messaging Social. Usa el mismo endpoint asíncrono que el canal de correo:

POST /api/v1/notifications
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Una respuesta 202 Accepted confirma que la notificación quedó encolada; no confirma que WhatsApp la haya entregado.

Campo Requerido Descripción
channel Debe ser whatsapp.
recipient Teléfono en formato E.164, por ejemplo +593999999999.
whatsapp_account_id No UUID de una cuenta del propietario autenticado. Si se omite, se usa su cuenta predeterminada.
whatsapp Objeto específico del tipo de mensaje.

Los campos de correo (subject, body, cc, bcc, body_type, template_id y smtp_account_id) no se usan para WhatsApp. En particular, el template_id de nivel superior pertenece a plantillas de correo; para WhatsApp usa whatsapp.template_id.

Las plantillas permiten iniciar una conversación o enviar cuando la ventana de atención está cerrada. La API recibe el UUID interno de la plantilla y valores nombrados; Summit Notify resuelve el nombre externo, idioma y componentes aprobados antes de encolar el mensaje.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp_account_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"whatsapp": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": {
"parameter_1": "Ana",
"parameter_2": "20 de agosto"
}
}
}

type puede omitirse cuando whatsapp.template_id está presente. La solicitud falla con 400 Bad Request si la plantilla no existe, pertenece a otra cuenta, no está aprobada o faltan valores.

En el editor de plantillas, cada componente tiene sus propias variables. La numeración del encabezado, el cuerpo y cada botón es independiente: {{1}} en el encabezado no comparte valor con {{1}} en el cuerpo o en una URL.

Los campos de ejemplo contienen valores concretos que Meta usa durante la revisión y que el panel usa para la vista previa. No escribas otra variable dentro de un ejemplo. Por ejemplo, Ana es válido; te esperamos {{1}} no lo es.

Las variables del cuerpo deben comenzar en {{1}}, ser consecutivas y no dejar huecos. Puede existir texto antes, entre o después de ellas. Por ejemplo:

Hola {{1}}, tu código de verificación es {{2}}.

Debajo del cuerpo se proporciona un ejemplo por línea y en el mismo orden:

Ana
123 456

Los ejemplos solo permiten que Meta revise la plantilla y que el panel genere su vista previa. No se guardan como valores permanentes para los envíos. En este caso, Summit Notify genera el siguiente esquema:

Variable en la plantilla Nombre para whatsapp.values Ejemplo de revisión
{{1}} del cuerpo parameter_1 Ana
{{2}} del cuerpo parameter_2 123 456

Al enviar una notificación debes proporcionar los valores reales:

{
"whatsapp": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": {
"parameter_1": "María",
"parameter_2": "847 291"
}
}
}

Las variables deben comenzar en {{1}}, ser consecutivas y no dejar huecos. Por ejemplo, {{1}} y {{3}} sin {{2}} no es válido. Cada valor requerido debe existir y no puede estar vacío.

El orden de las propiedades dentro de values no importa: Summit Notify usa sus nombres y las ordena según el esquema aprobado. Puedes consultar ese esquema mediante GET /api/v1/whatsapp-templates/{id}; la respuesta incluye parameters con component, position, name, type y required.

Otros componentes generan nombres diferentes:

Componente Variable admitida Nombre generado
Encabezado de texto Solo {{1}} header_parameter_1
Encabezado multimedia Imagen, video o documento header_media
Cuerpo {{1}}, {{2}}, … parameter_1, parameter_2, …
URL dinámica de un botón Debe terminar en {{1}} button_N_parameter_1, donde N comienza en 1 según la posición visual del botón

Para parámetros multimedia, el valor enviado en values debe ser una URL accesible. El pie de página no admite variables.

El encabezado puede omitirse o ser de texto, imagen, video o documento.

Formato Creación y ejemplo para revisión Valor requerido al enviar
Sin encabezado No requiere ejemplo. Ninguno.
Texto fijo No contiene variables. Ninguno.
Texto dinámico Admite únicamente {{1}} y exige un ejemplo concreto en el campo del encabezado. header_parameter_1.
Imagen Exige como ejemplo el handle de un archivo cargado para revisión en Meta. header_media con una URL HTTPS accesible.
Video Exige como ejemplo el handle de un archivo cargado para revisión en Meta. header_media con una URL HTTPS accesible.
Documento Exige como ejemplo el handle de un archivo cargado para revisión en Meta. header_media con una URL HTTPS accesible.

Una plantilla con este contenido:

Encabezado: Reserva {{1}}
Cuerpo: Hola, {{1}}. Tu reserva es el {{2}}.

necesita un ejemplo separado para el encabezado y dos líneas de ejemplos para el cuerpo:

Ejemplo del encabezado: R-4582
Ejemplos del cuerpo:
Ana
20 de agosto a las 19:00

El envío correspondiente usa tres propiedades diferentes:

{
"whatsapp": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": {
"header_parameter_1": "R-7831",
"parameter_1": "María",
"parameter_2": "22 de agosto a las 18:30"
}
}
}

El pie solo admite texto fijo. No genera propiedades en whatsapp.values. Si contiene {{1}} o cualquier otra variable, la creación se rechaza antes de enviarse a Meta.

Summit Notify admite hasta tres botones desde el panel. Cada botón puede ser de respuesta rápida, llamada telefónica o URL.

Tipo Configuración Valor requerido al enviar
Respuesta rápida Texto visible del botón. Ninguno.
Llamar a un número Texto y teléfono de destino. Ninguno.
URL estática Texto y URL completa sin variables. Ninguno.
URL dinámica La URL debe terminar exactamente en {{1}} y requiere un ejemplo del sufijo. button_N_parameter_1.

N identifica la posición visual del botón empezando en 1. Si el primer botón contiene https://example.com/reservas/{{1}}, el ejemplo podría ser R-4582 y el envío usaría:

{
"values": {
"button_1_parameter_1": "R-7831"
}
}

WhatsApp concatena ese valor al prefijo aprobado y abre https://example.com/reservas/R-7831. Una URL estática como https://example.com/reservas no acepta ni necesita una propiedad para el botón.

Cada botón debe tener texto. Los botones de llamada requieren teléfono y los de URL requieren una URL. Una URL dinámica con la variable en medio, más de una variable o sin ejemplo se rechaza.

Una plantilla puede tener cuerpo, encabezado, pie y botones completamente fijos. En ese caso no se escriben ejemplos de variables y el envío puede omitir values o enviar un objeto vacío:

{
"whatsapp": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e"
}
}

AUTHENTICATION no usa el esquema libre de las categorías UTILITY y MARKETING. Summit Notify genera automáticamente:

  • un cuerpo administrado por Meta con recomendación de seguridad;
  • un pie que indica una expiración de 10 minutos;
  • un botón OTP para copiar el código.

El cuerpo introducido en el panel debe contener exactamente una aparición de {{1}} y se debe proporcionar un ejemplo concreto, como 123456. No admite encabezado, pie personalizado ni botones convencionales. El texto escrito sirve para identificar y previsualizar la intención; el JSON enviado a Meta no incluye un campo text en el componente BODY, porque Meta genera el texto localizado.

En los envíos reales, el código se proporciona como parameter_1:

{
"whatsapp": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": {
"parameter_1": "847291"
}
}
}
Caso Resultado
El cuerpo contiene {{1}} y {{3}}, pero no {{2}}. Se rechaza por variables no consecutivas.
El cuerpo tiene dos variables y solo una línea de ejemplos. Se rechaza: debe existir un ejemplo por variable.
Un ejemplo contiene {{1}}. Se interpreta literalmente como ejemplo; no crea otra variable y debe reemplazarse por un valor concreto.
El encabezado de texto usa {{2}} o más de una variable. Se rechaza; solo admite una variable {{1}}.
El encabezado dinámico no tiene ejemplo. Se rechaza.
El encabezado multimedia no tiene handle de revisión. Se rechaza.
El pie contiene una variable. Se rechaza.
Una URL estática no tiene ejemplo. Es válida; no necesita valor durante el envío.
Una URL dinámica termina en {{1}} y tiene ejemplo. Es válida y genera button_N_parameter_1.
Una URL dinámica no termina en {{1}} o no tiene ejemplo. Se rechaza.
Falta una propiedad requerida en whatsapp.values o su valor está vacío. La solicitud de envío se rechaza con 400 Bad Request.
values contiene las propiedades en otro orden. Es válido; Summit Notify las ordena según el esquema guardado.
Se intenta personalizar encabezado, pie o botones de Authentication. Se rechaza; esos componentes están administrados por Meta.

Los tipos text, image, video, audio, document, location y reaction son mensajes libres. Solo se aceptan cuando el cliente escribió durante las últimas 24 horas. La cuenta debe tener meta_phone_number_id configurado.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp": {
"type": "text",
"text": {
"body": "Hola, ¿en qué podemos ayudarte?",
"preview_url": false
}
}
}

text.body es obligatorio y admite hasta 4096 caracteres.

image, video, audio y document aceptan exactamente una fuente: id o link.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp": {
"type": "document",
"document": {
"link": "https://media.example.com/documento.pdf",
"caption": "Documento solicitado",
"filename": "documento.pdf"
}
}
}

link debe ser una URL HTTPS pública que WhatsApp pueda descargar sin autenticación. caption y filename son opcionales. Un id identifica contenido previamente registrado en WhatsApp, por ejemplo mediante la carga multimedia del panel administrativo.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp": {
"type": "location",
"location": {
"latitude": -0.1807,
"longitude": -78.4678,
"name": "Punto de encuentro",
"address": "Quito, Ecuador"
}
}
}

La latitud debe estar entre -90 y 90; la longitud, entre -180 y 180. name y address son opcionales.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp": {
"type": "reaction",
"reaction": {
"message_id": "wamid.EXAMPLE",
"emoji": "👍"
}
}
}

reaction.message_id es obligatorio y debe identificar el mensaje al que se responde.

Un mensaje libre puede incluir fallback_template. Si la ventana de 24 horas está cerrada, Summit Notify sustituye el mensaje por esa plantilla aprobada. Si no hay fallback, responde 409 Conflict y no crea la notificación.

{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp": {
"type": "text",
"text": { "body": "Tu reserva está lista." },
"fallback_template": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": { "parameter_1": "Ana" }
}
}
}
{
"id": "7bf7e8e5-a9a9-46bc-9232-fb476efae2ad",
"channel": "whatsapp",
"status": "pending",
"attempts": 0,
"max_attempts": 3,
"created_at": "2026-08-13T18:30:00Z",
"updated_at": "2026-08-13T18:30:00Z"
}

Consulta GET /api/v1/notifications/{id} para observar el resultado. Después de pending puede aparecer processing, submitted, sent o failed. Los eventos delivered y read guardan marcas internas, pero el estado público permanece en sent.

Estado Causa habitual
400 Bad Request Teléfono inválido, payload incompleto, cuenta inexistente, plantilla no aprobada o valores de plantilla incorrectos.
401 Unauthorized Falta una identidad válida.
409 Conflict La conversación pertenece a otro tenant o la ventana está cerrada y no se proporcionó fallback.
500 Internal Server Error No fue posible guardar la notificación.

Consulta también Notificaciones, plantillas de WhatsApp y estado y errores.