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/notificationsAuthorization: Bearer YOUR_API_KEYContent-Type: application/jsonUna respuesta 202 Accepted confirma que la notificación quedó encolada; no confirma que WhatsApp la haya entregado.
Campos de la solicitud
Sección titulada «Campos de la solicitud»| Campo | Requerido | Descripción |
|---|---|---|
channel |
Sí | Debe ser whatsapp. |
recipient |
Sí | 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 |
Sí | 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.
Plantilla aprobada
Sección titulada «Plantilla aprobada»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.
Cómo se definen los parámetros
Sección titulada «Cómo se definen los parámetros»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:
Ana123 456Los 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.
Encabezado
Sección titulada «Encabezado»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:Ana20 de agosto a las 19:00El 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" } }}Pie de página
Sección titulada «Pie de página»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.
Botones
Sección titulada «Botones»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.
Plantillas sin variables
Sección titulada «Plantillas sin variables»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" }}Plantillas de autenticación
Sección titulada «Plantillas de autenticación»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" } }}Resumen de validaciones
Sección titulada «Resumen de validaciones»| 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. |
Mensajes dentro de la ventana de atención
Sección titulada «Mensajes dentro de la ventana de atención»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.
Multimedia
Sección titulada «Multimedia»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.
Ubicación
Sección titulada «Ubicación»{ "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.
Reacción
Sección titulada «Reacción»{ "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.
Fallback a una plantilla
Sección titulada «Fallback a una plantilla»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" } } }}Respuesta y seguimiento
Sección titulada «Respuesta y seguimiento»{ "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.
Errores frecuentes
Sección titulada «Errores frecuentes»| 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.