feat(whatsapp): webhook + envio por Graph API (F0)
Ultima fase del bot de reservas: conecta la maquina de conversacion ya existente (whatsapp-bot.ts) con la WhatsApp Business Cloud API. - src/lib/whatsapp.ts: traduce RespuestaBot -> payloads de Meta (texto e interactive/button, con los limites de 3 botones / 20 chars / 4096 chars), aplana el payload del webhook y valida X-Hub-Signature-256 en tiempo constante. - src/app/api/whatsapp/webhook/route.ts: GET de verificacion y POST de mensajes. Valida la firma sobre el cuerpo crudo, deduplica por message id (Meta reintenta) y siempre devuelve 200 para no entrar en loop de retries. - scripts/test-whatsapp-envio.ts (npm run test:envio): 30 asserts sobre la capa Meta con fetch stubbeado, sin DB ni credenciales. - docs/whatsapp.md con el alta en el panel de Meta y las 4 env vars. Falta solo cargar las credenciales de Meta en el .env de produccion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# Bot de reservas por WhatsApp
|
||||
|
||||
Flujo: el cliente escribe al número del taller → el bot lo identifica por teléfono (verifica
|
||||
con el email registrado, o lo da de alta) → elige mecánico, trabajo y horario → confirma y se
|
||||
crea el Turno. Todo pasa dentro de la ventana de 24hs que abre el cliente, así que **no hacen
|
||||
falta plantillas aprobadas** ni tiene costo.
|
||||
|
||||
## Piezas
|
||||
|
||||
| Archivo | Qué hace |
|
||||
|---|---|
|
||||
| `src/lib/whatsapp-bot.ts` | Máquina de conversación. No sabe nada de Meta: devuelve `RespuestaBot[]` |
|
||||
| `src/lib/whatsapp.ts` | Traduce a/desde la Graph API de Meta y valida la firma del webhook |
|
||||
| `src/app/api/whatsapp/webhook/route.ts` | Endpoint: verificación (GET) y mensajes entrantes (POST) |
|
||||
|
||||
Tests sin DB ni credenciales: `npm run test:bot` (conversación) y `npm run test:envio` (capa Meta).
|
||||
|
||||
## Variables de entorno
|
||||
|
||||
```
|
||||
WHATSAPP_PHONE_NUMBER_ID= # id numérico del número, NO el teléfono
|
||||
WHATSAPP_TOKEN= # token permanente de System User
|
||||
WHATSAPP_VERIFY_TOKEN= # string inventado, el mismo acá y en el panel de Meta
|
||||
WHATSAPP_APP_SECRET= # App -> Settings -> Basic -> App Secret
|
||||
```
|
||||
|
||||
Sin `WHATSAPP_APP_SECRET` el webhook rechaza todo con 403 (es a propósito: sin firma no se
|
||||
puede confiar en el payload).
|
||||
|
||||
## Alta en Meta (una sola vez)
|
||||
|
||||
1. Meta Business Suite con la cuenta de Facebook del taller.
|
||||
2. developers.facebook.com → crear App tipo **Business** → agregar producto **WhatsApp**.
|
||||
3. **WhatsApp → API Setup**: de ahí salen `PHONE_NUMBER_ID` y un token temporal (24hs).
|
||||
Para el token definitivo: Business Settings → System Users → crear usuario → Generate Token
|
||||
con permisos `whatsapp_business_messaging` y `whatsapp_business_management`.
|
||||
4. **App → Settings → Basic → App Secret** → `WHATSAPP_APP_SECRET`.
|
||||
5. Cargar las 4 variables en el `.env` de producción y redeployar.
|
||||
6. **WhatsApp → Configuration → Webhook**:
|
||||
- Callback URL: `https://taller.beldo.duckdns.org/api/whatsapp/webhook`
|
||||
- Verify token: el mismo `WHATSAPP_VERIFY_TOKEN`
|
||||
- Suscribir el campo **`messages`** (sin esto no llega nada).
|
||||
7. Probar con el número de prueba que da Meta gratis, antes de migrar el número real.
|
||||
|
||||
Notas:
|
||||
- El número del taller no puede estar activo en la app de WhatsApp normal/Business: hay que
|
||||
borrar esa cuenta antes de migrarlo a Cloud API.
|
||||
- Business Verification se saltea mientras estemos abajo de 1000 usuarios únicos/24hs; solo
|
||||
hace falta la aprobación del **Display Name**.
|
||||
- Meta permite 3 botones como máximo. Si hay más de 3 mecánicos activos, salen los 3 primeros
|
||||
como botón y el resto se elige respondiendo con el número (el bot acepta las dos formas).
|
||||
Reference in New Issue
Block a user