# Webhook de WhatsApp

_Migrado de `WEBHOOK_ENDPOINTS.md` (raíz del repositorio), donde vivía suelto._


## Endpoint principal

```
URL: /api/webhook.php
```

---

## GET — Verificación de webhook

```
GET /api/webhook.php?hub.mode=subscribe&hub.verify_token=TOKEN&hub.challenge=CHALLENGE
```

### Parámetros que envía Meta
| Parámetro | Valor esperado |
|---|---|
| `hub.mode` | `subscribe` |
| `hub.verify_token` | El token configurado en `system_config.webhook_verify_token` |
| `hub.challenge` | Número aleatorio que debe devolverse tal cual |

### ⚠️ Bug conocido
El código lee `$_GET['hub_verify_token']` (con guión bajo), pero PHP convierte los puntos a guiones bajos automáticamente al parsear `$_GET`, por lo que **funciona correctamente**.

### Respuesta exitosa
```
HTTP 200
Body: {challenge}
```

### Respuesta fallida
```
HTTP 403
Body: {"error":"Token de verificación inválido"}
```

---

## POST — Recepción de eventos

```
POST /api/webhook.php
Content-Type: application/json
```

### Estructura del payload esperado (Meta Cloud API)

```json
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WABA_ID",
    "changes": [{
      "field": "messages",
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "phone_number_id": "PHONE_NUMBER_ID"
        },
        "contacts": [{
          "wa_id": "573001234567",
          "profile": { "name": "Nombre Contacto" }
        }],
        "messages": [{
          "from": "573001234567",
          "id": "wamid.XXX",
          "timestamp": "1234567890",
          "type": "text",
          "text": { "body": "Hola" }
        }]
      }
    }]
  }]
}
```

### Tipos de mensaje soportados
| `type` | Descripción |
|---|---|
| `text` | Texto plano |
| `image` | Imagen (con caption opcional) |
| `audio` | Audio / nota de voz |
| `video` | Video |
| `document` | Documento / PDF |
| `sticker` | Sticker |
| `reaction` | Reacción emoji a otro mensaje |
| `interactive` | Respuesta de lista o botón |

### El campo `field` del change puede ser
- `messages` → mensajes entrantes y estados
- `conversations` → alias aceptado también

### Eventos de estado (statuses)
```json
"statuses": [{
  "id": "wamid.XXX",
  "status": "sent|delivered|read|failed",
  "recipient_id": "573001234567"
}]
```

### Respuesta exitosa
```
HTTP 200
Body: {"status":"success"}
```

---

## Configuración necesaria en `system_config` (BD)

| config_key | Descripción |
|---|---|
| `whatsapp_token` | Access Token de Meta |
| `whatsapp_phone_number_id` | Phone Number ID de la línea |
| `webhook_verify_token` | Token de verificación del webhook |
| `whatsapp_api_url` | `https://graph.facebook.com/v22.0/` |

---

## Variables de entorno equivalentes (`.env`)

```env
WHATSAPP_TOKEN=
WHATSAPP_PHONE_NUMBER_ID=
WEBHOOK_VERIFY_TOKEN=
WHATSAPP_API_URL=https://graph.facebook.com/v22.0/
DB_HOST=
DB_PORT=3306
DB_NAME=
DB_USER=
DB_PASS=
```

---

## Tablas BD que usa el webhook

| Tabla | Uso |
|---|---|
| `users` | Crea o busca usuario por `phone_number` |
| `conversations` | Guarda cada mensaje (deduplicado por `message_id`) |
| `webhook_logs` | Registra el payload crudo de cada POST |
| `notifications` | Crea aviso de nuevo mensaje entrante |
| `media_queue` | Encola media que no pudo descargarse en el momento |
| `system_config` | Lee tokens y configuración |

---

## Seguridad — pendiente de implementar

- No valida la firma `X-Hub-Signature-256` en el POST.
- Se recomienda agregar antes de procesar:
```php
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
$expected  = 'sha256=' . hash_hmac('sha256', $input, APP_SECRET);
if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit;
}
```
