Ir al contenido

Canal WhatsApp

Summit Notify entrega WhatsApp mediante AWS End User Messaging Social. Las cuentas, plantillas, conversaciones y eventos se aíslan por la identidad autenticada.

Para el contrato de envío de POST /api/v1/notifications, consulta Enviar notificaciones por WhatsApp. Esta página conserva la configuración de cuentas, plantillas, eventos y adjuntos.

Una cuenta WhatsApp contiene:

Campo Descripción
ownership_type notify_managed o customer_owned.
aws_region Región utilizada por el cliente de AWS.
waba_id Identificador de la WABA enlazada en AWS.
origination_phone_number_id Identificador AWS que empieza por phone-number-id-.
meta_waba_id Identificador numérico de Meta usado para enrutar eventos.
meta_phone_number_id Identificador numérico del número en Meta y las conversaciones.
is_default Cuenta usada cuando se omite whatsapp_account_id.

Las cuentas se administran actualmente desde /admin/whatsapp-accounts; no existe un CRUD público /api/v1/whatsapp-accounts.

Variable Propósito
WHATSAPP_META_API_VERSION Versión de Meta enviada a AWS.
WHATSAPP_TEMPLATE_SYNC_INTERVAL Frecuencia de reconciliación de plantillas.
WHATSAPP_SNS_TOPIC_ARN ARN exacto del topic SNS permitido.
WHATSAPP_MEDIA_BUCKET Bucket privado para adjuntos entrantes. Vacío deshabilita la recuperación protegida.
WHATSAPP_MEDIA_REGION Región del bucket y la WABA.
WHATSAPP_MEDIA_PREFIX Prefijo S3; valor usual notify/whatsapp.
WHATSAPP_MEDIA_CLOUDFRONT_URL Dominio HTTPS de la distribución.
CLOUDFRONT_PUBLIC_KEY_ID ID de la clave pública confiable, no el ID del grupo ni de la distribución.
CLOUDFRONT_PRIVATE_KEY_PATH Ruta interna al PEM RSA usado para firmar URLs.
WHATSAPP_MEDIA_URL_TTL Vigencia de una URL firmada, por ejemplo 10m.

Cuando WHATSAPP_MEDIA_BUCKET tiene valor, región, URL CloudFront, ID público y ruta privada son obligatorios. La clave privada debe montarse en modo sólo lectura y permanecer fuera del repositorio y de la imagen Docker.

La identidad AWS del proceso necesita las operaciones Social Messaging utilizadas por la instancia, incluidas social-messaging:SendWhatsAppMessage, social-messaging:PostWhatsAppMessageMedia y social-messaging:GetWhatsAppMessageMedia. Para los objetos necesita s3:PutObject bajo el prefijo configurado; CloudFront debe leer mediante OAC con s3:GetObject. No agregues s3:HeadObject: esa acción no existe en IAM y las solicitudes HEAD se autorizan mediante s3:GetObject.

Además del panel, las conversaciones se pueden operar desde sistemas externos y desde agentes de Summit AI. Ambas rutas usan la API key de Summit Notify (Authorization: Bearer <SUMMIT_NOTIFY_API_KEY>) y respetan el mismo aislamiento por propietario.

Método Ruta Descripción
GET /api/v1/whatsapp-conversations Lista paginada por cursor. Filtros: window=open|closed, q=<teléfono>, limit (1–100, default 25), cursor.
GET /api/v1/whatsapp-conversations/{id} Detalle de la conversación.
GET /api/v1/whatsapp-conversations/{id}/messages Historial (limit, default 100, máx 500) con window_open y service_window_expires_at.
POST /api/v1/whatsapp-conversations/{id}/reply Encola una respuesta; devuelve 202 con {"notification_id": "..."}.
POST /api/v1/whatsapp-conversations/{id}/media-upload Sube un adjunto (multipart file + media_type, máx 20 MB) y devuelve 201 con el media_id.
GET /api/v1/whatsapp-conversations/{id}/messages/{messageID}/media Devuelve JSON con URL firmada de CloudFront (url, expires_at, content_type, filename). Responde 503 con Retry-After mientras se copia a S3.

El cuerpo de reply admite message_type (text, image, video, audio, document, location), text, media_id (de un media-upload previo) o media_url (HTTPS pública), caption, filename, latitude, longitude, location_name, address, y opcionalmente fallback_template_id con fallback_parameters. Si la ventana de 24 horas está cerrada y no hay fallback válido, responde 409; los errores de validación responden 400.

Summit AI puede invocar las conversaciones como tools MCP en el endpoint:

POST /mcp
Authorization: Bearer SUMMIT_NOTIFY_API_KEY
Tool Descripción
list_conversations Lista conversaciones del tenant. Filtros: window, q, limit, cursor.
get_conversation Detalle de una conversación por UUID.
get_conversation_messages Historial de mensajes.
reply_to_conversation Encola una respuesta; devuelve notification_id y status.

Los tools aplican las mismas reglas de ventana y fallback que los endpoints JSON. No soportan carga/descarga de archivos binarios; usá los endpoints JSON para multimedia. Consulta la referencia MCP de Summit Notify.

Usa el endpoint común:

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

Campos superiores:

Campo Requerido Descripción
channel Debe ser whatsapp.
recipient Teléfono E.164, por ejemplo +593999999999.
whatsapp_account_id No UUID de la cuenta; se usa la predeterminada si se omite.
whatsapp Payload específico del canal.
{
"channel": "whatsapp",
"recipient": "+593999999999",
"whatsapp_account_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"whatsapp": {
"type": "text",
"text": { "body": "Hola, ¿en qué podemos ayudarte?" },
"fallback_template": {
"type": "template",
"template_id": "c7a4e210-9d2b-4f6a-8e1c-3b5d7f9a0c2e",
"values": { "parameter_1": "Cliente" }
}
}
}

El texto admite hasta 4096 caracteres. El mensaje libre exige una conversación con ventana de servicio abierta; de lo contrario responde 409 Conflict o utiliza fallback_template.

image, video, audio y document aceptan exactamente uno de id o link:

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

El enlace debe ser HTTPS y accesible para WhatsApp.

El panel permite subir el archivo directamente. El endpoint autenticado acepta multipart, limita el archivo a 20 MB, lo guarda bajo el prefijo outbound, invoca PostWhatsAppMessageMedia y devuelve el mediaId. El formulario envía después ese ID en lugar de una URL. El mismo endpoint recibe los blobs creados por el grabador del navegador.

La migración 0020_add_whatsapp_media_uploads.sql registra propietario, cuenta, conversación, mediaId, clave S3, MIME, nombre y tamaño. Cuando el worker confirma el envío, el mensaje saliente recupera esa asociación y continúa mostrando el adjunto después de actualizar la conversación.

La ubicación requiere coordenadas válidas. Una reacción requiere el ID del mensaje al que responde:

{
"type": "reaction",
"reaction": { "message_id": "wamid.EXAMPLE", "emoji": "👍" }
}
Método Ruta Éxito
GET /api/v1/whatsapp-templates 200
POST /api/v1/whatsapp-templates 201
GET /api/v1/whatsapp-templates/{id} 200
POST /api/v1/whatsapp-templates/{id}/sync 200
DELETE /api/v1/whatsapp-templates/{id} 200

Estos endpoints usan un access token OpenID Connect. La creación se envía inmediatamente a AWS/Meta. Sólo los estados remotos APPROVED o ACTIVE establecen can_send: true.

El API de notificaciones recibe el template_id interno y valores con nombre; resuelve internamente el nombre externo, idioma y componentes para evitar que el consumidor suplante la definición aprobada.

El endpoint público es:

POST /webhooks/aws/sns/whatsapp

Acepta confirmaciones y notificaciones únicamente desde el Topic ARN configurado. Valida la firma SNS y procesa duplicados de forma idempotente. La notificación pasa por submitted, sent o failed; los eventos delivered y read registran sus fechas manteniendo el estado sent. Los mensajes entrantes abren o renuevan conversaciones.

Los mensajes multimedia conservan el mediaId y un estado local: pending, retrieving, available, failed o expired. El endpoint autenticado del panel recupera bajo demanda el archivo hacia S3 y redirige a una URL firmada de CloudFront. El bucket, WABA y llamada de AWS deben operar en la misma cuenta y región.

La clave S3 sigue esta estructura:

{prefix}/{whatsapp-account-id}/{conversation-id}/{message-id}/{media-id}.{extension}

Los mensajes antiguos se incorporan mediante la migración de metadatos siempre que el payload almacenado conserve el mediaId.