# Messenger Webhook Setup (2026-08-01)

## What's Built

Real-time chat events endpoint that replaces the 3h polling cron:

- **GET** `https://adsfb.namnan.co.th/webhook/messenger` — verification
- **POST** `https://adsfb.namnan.co.th/webhook/messenger` — receive events

Events supported:
- `message` (incoming/outgoing text + attachments)
- `delivery` (watermarks)
- `read` (read receipts)
- `postback` (button clicks)

## Manual Meta App Setup (5 minutes)

### 1. Configure Webhook URL

1. Go to https://developers.facebook.com/apps/
2. Select your app (the one with `ads_management` permission)
3. Left menu: **Add a Product** → **Webhooks** (if not already added)
4. Click **Webhooks** → **Page** → **Edit Subscription**
5. **Callback URL**: `https://adsfb.namnan.co.th/webhook/messenger`
6. **Verify Token**: `sj88_chat_webhook_2026`
7. Click **Verify and Save**

### 2. Subscribe Fields

For "Page" webhook, subscribe to:
- ✅ `messages`
- ✅ `messaging_postbacks`
- ✅ `message_deliveries`
- ✅ `message_reads`
- ✅ `messaging_referrals` (optional, for ads)

Click "Subscribe" for each.

### 3. Subscribe Each Page to Webhooks

For EACH page (run once per page):

```bash
# Get page access token first
curl "https://graph.facebook.com/v20.0/<PAGE_ID>?fields=access_token&access_token=<USER_TOKEN>"
```

Then:
```bash
curl -X POST "https://graph.facebook.com/v20.0/<PAGE_ID>/subscribed_apps" \
  -H "Content-Type: application/json" \
  -d '{
    "subscribed_fields": ["messages", "messaging_postbacks", "message_deliveries", "message_reads"],
    "access_token": "<PAGE_ACCESS_TOKEN>"
  }'
```

Expected response: `{"success": true}`

### 4. Verify

Send a message to any subscribed page. Check the server log:
```bash
tail -f /tmp/adsfb_v3.log | grep webhook
```

Should see: `[webhook] message from user ...`

## Source Tracking

Messages saved by webhook have `source = 'webhook'` in `chat_messages` table.
Poller messages have `source = 'poller:3h'`.

Useful queries:
```sql
-- Webhook events count
SELECT COUNT(*) FROM chat_messages WHERE source = 'webhook';

-- Recent webhook events
SELECT * FROM chat_messages WHERE source LIKE 'webhook%' ORDER BY received_at DESC LIMIT 20;
```

## Limitations (Phase 12)

1. **No backward-replay** — webhooks only deliver events after subscription. Old messages still come from poller.
2. **No sender name** — `sender_name` is NULL for webhook events. Need extra Graph API call to resolve. Add later.
3. **Conversation ID format** — webhook uses `t_<user_id>`, poller uses same. Compatible.
4. **No delivery/read backfill** — poller runs every 3h as backup.
5. **Rate limit** — Meta webhook rate limit is 50 deliveries/sec/app, we have 67 pages, may need batching.

## Rollback

If webhook causes issues:
1. Remove webhook URL in Meta Dashboard
2. Poller continues running (every 3h)
3. Messages keep flowing

Webhooks are **additive** — they don't disable polling.

## Files

- `/opt/adsfb/src/routes/webhookMessenger.ts` — endpoint logic
- `/opt/adsfb/src/index.ts` — registered at lines 67 + 162
- `/etc/nginx/sites-enabled/adsfb.namnan.co.th` — `/webhook/` location (proxy to :22222)

## Test Commands

```bash
# Verify (should return challenge)
curl "https://adsfb.namnan.co.th/webhook/messenger?hub.mode=subscribe&hub.verify_token=sj88_chat_webhook_2026&hub.challenge=OK"

# Simulate message event
curl -X POST "https://adsfb.namnan.co.th/webhook/messenger" \
  -H "Content-Type: application/json" \
  -d '{
    "object": "page",
    "entry": [{
      "id": "102601625742282",
      "messaging": [{
        "sender": {"id": "test_user"},
        "recipient": {"id": "102601625742282"},
        "message": {"mid": "m_test_001", "text": "hello"}
      }]
    }]
  }'

# Verify saved
curl "https://adsfb.namnan.co.th/public/chat-conversation-messages?conversationId=t_test_user&limit=3"
```
