Skip to main content

WhatsApp Channel Runbook

Operational procedures for the Norns WhatsApp channel.

Service Overview

ComponentLocationPurpose
WhatsApp Moduleservices/norns/agent/whatsapp/Message handling
Twilio APIExternal SaaSWhatsApp gateway
PostgreSQLwhatsapp_sessions tableSession tracking
RedisCache layerSession window cache

Health Checks

Quick Status Check

# Check Norns container status
ssh ravenhelm@100.115.101.81 "docker ps | grep norns"

# Check WhatsApp-related logs
ssh ravenhelm@100.115.101.81 "docker logs norns-agent 2>&1 | grep -i whatsapp | tail -10"

# Verify webhook endpoint is responding
curl -I https://norns-pm.ravenhelm.dev/whatsapp/webhook

Verify Template Configuration

# Check templates are loaded in container
ssh ravenhelm@100.115.101.81 "docker exec norns-agent env | grep WA_TEMPLATE"

# List templates via API
curl -s "https://norns-pm.ravenhelm.dev/api/whatsapp/templates" \
-H "X-API-Key: $NORNS_API_KEY" | jq

Verify Session Tracking

# Check session table
ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c 'SELECT phone_number, window_expires_at, last_inbound_at FROM whatsapp_sessions ORDER BY last_inbound_at DESC LIMIT 5;'"

# Check Redis connectivity
ssh ravenhelm@100.115.101.81 "docker exec redis redis-cli ping"

Common Operations

Add User Phone Number

# Find user
ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c \"SELECT user_id, display_name, email FROM users;\""

# Add phone number (E.164 format)
ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c \"UPDATE users SET phone_number = '+1XXXXXXXXXX' WHERE user_id = 'uuid-here';\""

Send Test Template Message

curl -X POST "https://norns-pm.ravenhelm.dev/api/whatsapp/send" \
-H "X-API-Key: $NORNS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "701973d2-57e4-4c84-a2ec-ded996dcf676",
"template_name": "task_reminder",
"variables": {
"task_name": "Test reminder",
"due_time": "now"
}
}'

Check Session Window Status

# Via API
curl "https://norns-pm.ravenhelm.dev/api/whatsapp/session/+1234567890" \
-H "X-API-Key: $NORNS_API_KEY" | jq

# Via database
ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c \"SELECT *, CASE WHEN window_expires_at > NOW() THEN 'IN_WINDOW' ELSE 'OUTSIDE_WINDOW' END as status FROM whatsapp_sessions WHERE phone_number = '+1234567890';\""

View Twilio Message Logs

# Recent messages (via Twilio CLI)
twilio api:messaging:v1:messages:list --limit 10

# Messages to/from specific number
twilio api:messaging:v1:messages:list --to "whatsapp:+1234567890" --limit 5

Troubleshooting

Issue: Messages Not Being Received

Symptoms: User sends WhatsApp message, no response from Norns

Diagnosis:

  1. Check if webhook is receiving requests:

    ssh ravenhelm@100.115.101.81 "docker logs norns-agent 2>&1 | grep 'whatsapp/webhook' | tail -10"
  2. Check Twilio webhook configuration:

    • Go to Twilio Console → Messaging → WhatsApp Sandbox
    • Verify webhook URL: https://norns-pm.ravenhelm.dev/whatsapp/webhook
  3. Verify sandbox membership:

    • User must send join <code> to sandbox number
    • Check Twilio Console for sandbox participants

Resolution:

  • If webhook not configured: Update Twilio sandbox settings
  • If user not in sandbox: Have user rejoin with join <code>
  • If webhook errors: Check Norns container logs for stack traces

Issue: Template Messages Failing

Symptoms: Proactive messages not delivered, API returns error

Diagnosis:

  1. Check template SID is configured:

    ssh ravenhelm@100.115.101.81 "docker exec norns-agent env | grep WA_TEMPLATE_TASK_REMINDER"
  2. Verify template exists in Twilio:

    twilio api:content:v1:content:fetch --sid HX685da4c35863ed1180fb46bb8e99004b
  3. Check variable mapping:

    • API uses named variables: {"task_name": "...", "due_time": "..."}
    • Template uses positional: {"1": "...", "2": "..."}

Resolution:

  • If SID missing: Add to secrets/.env and restart container
  • If template doesn't exist: Create new template via Twilio API
  • If variable mismatch: Update template_manager.py variable mapping

Issue: Session Window Not Tracking

Symptoms: All messages require templates, window never opens

Diagnosis:

  1. Check Redis is running:

    ssh ravenhelm@100.115.101.81 "docker exec redis redis-cli ping"
  2. Check session table:

    ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c 'SELECT * FROM whatsapp_sessions;'"
  3. Check session tracker logs:

    ssh ravenhelm@100.115.101.81 "docker logs norns-agent 2>&1 | grep -i session | tail -20"

Resolution:

  • If Redis down: Restart Redis container
  • If no sessions: Verify record_inbound() is being called in webhook handler
  • If expired immediately: Check server time sync

Issue: User Not Found by Phone

Symptoms: Webhook receives message but can't resolve user

Diagnosis:

  1. Check phone format (must be E.164):

    ssh ravenhelm@100.115.101.81 "docker logs norns-agent 2>&1 | grep 'resolve_user' | tail -5"
  2. Check user has phone number:

    ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d ravenmaskos -c \"SELECT user_id, phone_number FROM users WHERE phone_number IS NOT NULL;\""

Resolution:

  • Add phone number to user record with correct E.164 format

Restart Procedures

Restart Norns Container

ssh ravenhelm@100.115.101.81 "cd ~/ravenhelm/docs/AI-ML-Platform/norns-agent && docker compose restart norns"

# Verify restart
ssh ravenhelm@100.115.101.81 "docker logs norns-agent 2>&1 | tail -20"

Full Stack Restart

ssh ravenhelm@100.115.101.81 "cd ~/ravenhelm/docs/AI-ML-Platform/norns-agent && docker compose down && docker compose up -d"

Twilio Sandbox Management

View Sandbox Settings

  1. Go to Twilio Console
  2. Navigate to: Messaging → Try it out → Send a WhatsApp message
  3. Note sandbox code and webhook URLs

Update Sandbox Webhooks

  1. When a message comes in: https://norns-pm.ravenhelm.dev/whatsapp/webhook
  2. Status callback URL: https://norns-pm.ravenhelm.dev/whatsapp/status

Add New Sandbox Participant

  1. Share sandbox join code with user
  2. User sends join <code> to +1 415 523 8886
  3. User receives confirmation
  4. Add phone number to their user record in database

Template Management

List All Templates

twilio api:content:v1:content:list

Create New Template

curl -X POST "https://content.twilio.com/v1/Content" \
-u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"friendly_name": "new_template_name",
"language": "en",
"variables": {"1": "variable_name"},
"types": {
"twilio/text": {
"body": "Your message with {{1}}"
}
}
}'

After creating, add the returned SID to:

  1. secrets/.env as WA_TEMPLATE_NEW_NAME=HXXXXXXXXXXX
  2. docker-compose.yml environment section
  3. template_manager.py template registry
  4. Restart Norns container

Delete Template

twilio api:content:v1:content:remove --sid HXXXXXXXXXXX

Monitoring

Key Metrics to Watch

  1. Webhook Response Time - Should be < 1s
  2. Message Delivery Rate - Check Twilio dashboard
  3. Session Window Coverage - % of messages sent in-window vs template

Log Locations

LogCommand
Norns WhatsAppdocker logs norns-agent 2>&1 | grep -i whatsapp
Twilio webhooksTwilio Console → Monitor → Logs
Database queriesdocker logs postgres 2>&1
  • [[AI-ML-Platform/Norns-WhatsApp-Channel|WhatsApp Channel Overview]]
  • [[AI-ML-Platform/Norns-Agent|Norns Agent]]
  • [[AI-ML-Platform/Norns-Telephony|Norns Telephony]]