Install
openclaw skills install whatsapp-business-aiAutomates WhatsApp conversations for local businesses — replies, bookings, lead capture, and follow-ups. Designed for gyms, restaurants, salons, clinics, and service-based businesses.
openclaw skills install whatsapp-business-aiAutomates WhatsApp conversations for local businesses — handling replies, booking inquiries, lead capture, and intelligent follow-ups without requiring 24/7 human attention. Designed for gyms, restaurants, salons, clinics, and service-based businesses in South Africa.
| Requirement | Version/Detail |
|---|---|
| OpenClaw | v2.4+ |
| Node.js | v18+ |
| WhatsApp Business API (Meta) | Approved business account |
| Meta Developer App | With WhatsApp product configured |
| Python 3 | v3.10+ (for NLP pipeline) |
wacli CLI | Installed on host |
| ngrok or static IP | For webhook callback |
cp -r streams/01_ClawHub_Skills/01_WhatsApp_Business_AI_Assistant/* ~/.openclaw/skills/
cd ~/.openclaw/skills/whatsapp-business-ai
npm install
pip install -r requirements.txt
Create ~/.openclaw/skills/whatsapp-business-ai/.env:
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
WHATSAPP_ACCESS_TOKEN=your_permanent_token
WHATSAPP_VERIFY_TOKEN=your_webhook_verify_token
WHATSAPP_BUSINESS_ACCOUNT_ID=your_business_account_id
BUSINESS_HOURS_TIMEZONE=Africa/Johannesburg
DEFAULT_LANGUAGE=en
NLP_MODEL_PATH=./models/za_intent_classifier
LEAD_DB_PATH=./data/leads.db
BOOKING_CALENDAR_ID=your_google_calendar_id
# Verify wacli is available
which wacli || brew install wacli
wacli --configure
# Start webhook receiver (uses ngrok for dev)
./scripts/start-webhook.sh
# Register webhook with Meta
curl -X POST "https://graph.facebook.com/v18.0/$WHATSAPP_PHONE_NUMBER_ID/subscriptions" \
-H "Authorization: Bearer $WHATSAPP_ACCESS_TOKEN" \
-d "object=whatsapp_business_account&callback_url=https://your-ngrok-url.ngrok.io/webhook&verify_token=$WHATSAPP_VERIFY_TOKEN"
# Production mode
openclaw skill run whatsapp-business-ai
# Development / dry-run
openclaw skill run whatsapp-business-ai --dry-run
The assistant runs as a persistent OpenClaw process that:
Incoming Message → Intent Classifier → Response Generator → Send Reply
↓
Booking Detected?
├── Yes → Check Calendar → Confirm Slot → Add Booking
└── No → Lead? → Log Lead → Schedule Follow-up
| Command | Description |
|---|---|
/status | Show assistant health, queue depth, message count today |
/leads | Export leads as CSV or JSON |
/analytics | Last 24h: sent/replied/followed-up counts |
/blacklist <phone> | Block a number |
/broadcast | Send bulk message to all leads (ask first) |
/pause | Stop accepting new messages (resume with /resume) |
Auto-reply templates are in ./templates/. Customise per business type:
templates/
├── auto_replies/
│ ├── booking_gym.yaml
│ ├── booking_restaurant.yaml
│ ├── booking_salon.yaml
│ ├── greeting_day.yaml
│ ├── greeting_night.yaml
│ ├── hours_inquiry.yaml
│ ├── pricing_inquiry.yaml
│ ├── complaint_acknowledgement.yaml
│ └── out_of_hours.yaml
├── follow_ups/
│ ├── no_reply_24h.yaml
│ ├── abandoned_booking.yaml
│ ├── post_service_feedback.yaml
│ └── promotion_blast.yaml
└── intents.yaml
Example: booking_gym.yaml
name: gym_booking
trigger:
intents: [booking, tour_inquiry, membership_inquiry]
confidence_threshold: 0.75
response:
template: |
Hi {{customer_name}}! 👋
Thanks for reaching out to {{business_name}}.
I can help you book:
🏋️ A free trial session
📋 A membership consultation
🎯 A personal training intro
What time works for you? Our hours are:
Mon–Fri: 5:00 AM – 9:00 PM
Sat: 6:00 AM – 6:00 PM
Sun: 7:00 AM – 2:00 PM
Just tell me your preferred day and time!
buttons:
- "Book Trial"
- "See Pricing"
- "Ask a Human"
Edit ./config/prompts.yaml:
classifier_prompt: |
Classify the incoming WhatsApp message into exactly one intent.
Intents: [booking, pricing_inquiry, hours, complaint, lead, general, spam]
Context: {business_type} in {location}
Message: {text}
Respond with only the intent name and confidence score.
response_prompt: |
You are {assistant_name}, the friendly AI assistant for {business_name}.
Location: {location}
Business type: {business_type}
Business hours: {hours}
Customer message: {text}
Detected intent: {intent}
Reply in a warm, professional tone. Be concise. If it's a booking,
ask for time and contact info. Never give away pricing you're unsure of.
Use South African English.
"Hey Marvis, can you check on the gym assistant? How many unqualified leads are waiting?" "Set up a new WhatsApp assistant for 'Jozi Cuts Barbershop' in Randburg." "What's the reply rate on the restaurant assistant this week?" "Add a 'Student Discount' promotion template to the gym assistant's broadcast queue."
whatsapp-business-ai/
├── SKILL.md
├── README.md
├── config/
│ ├── business.yaml # Business profile (name, hours, location, type)
│ ├── prompts.yaml # LLM prompts for classification & reply
│ └── webhooks.yaml # Webhook routing rules
├── templates/
│ ├── auto_replies/ # Pre-written reply templates
│ ├── follow_ups/ # Scheduled follow-up templates
│ └── intents.yaml # Intent definitions & training data
├── scripts/
│ ├── start-webhook.sh # Start webhook listener with ngrok
│ ├── register-webhook.sh # Register with Meta APIs
│ └── export-leads.py # Export leads to CSV
├── workflows/
│ ├── booking.yaml # Booking: detect → confirm → create
│ ├── lead.yaml # Lead: capture → enrich → follow-up
│ └── complaint.yaml # Complaint: acknowledge → escalate → resolve
├── data/
│ ├── leads.db # SQLite lead database
│ └── conversation_logs/ # Raw conversation transcripts (rotated)
├── requirements.txt
└── package.json
| Symptom | Likely Cause | Fix |
|---|---|---|
| Assistant not replying | Webhook not registered | Run register-webhook.sh |
| Replies go to wrong chat | Wrong phone_number_id in env | Check .env values |
| "Message not allowed" | Sender hasn't opted in | Send template message first |
| Low confidence on intent | Trained on wrong business type | Update config/business.yaml |
| Calendar sync fails | Missing Google Calendar scope | Re-auth with https://www.googleapis.com/auth/calendar scope |
| Leads not saving | SQLite path not writable | chmod 755 ./data/ |
| ngrok URL changed | Free ngrok rotates on restart | Use paid plan or static IP |