Why WhatsApp?
In Zimbabwe, WhatsApp isn't just a messaging app—it's the internet. With 80%+ penetration versus 15% for other apps, building anywhere else means building for nobody.
BookBot started as a web app. Beautiful UI. Great UX. Zero users. When I moved to WhatsApp, adoption was immediate.
The Architecture
BookBot is a stateful conversational agent built with:
- Pydantic AI for agent orchestration
- Claude API for natural language understanding
- WhatsApp Business API via Twilio
- State machine for conversation flow
The State Machine Approach
Don't rely purely on LLMs for conversation flow. Use a state machine:
class BookingState(Enum):
GREETING = "greeting"
COLLECTING_SERVICE = "collecting_service"
COLLECTING_DATE = "collecting_date"
COLLECTING_TIME = "collecting_time"
CONFIRMING = "confirming"
COMPLETE = "complete"
The LLM handles intent extraction. The state machine handles flow control.
Lessons Learned
1. SMS Fallback is Essential
40% of conversations get interrupted when data runs out. SMS fallback saved those bookings:
async def send_message(user_id: str, message: str):
try:
await whatsapp.send(user_id, message)
except WhatsAppError:
await sms.send(user_id, message) # Fallback
2. Expect Chaos
Users send voice notes. They send photos. They reply "yes" to multiple choice questions. Build for chaos:
async def parse_intent(message: Message) -> Intent:
if message.type == "voice":
text = await transcribe(message.audio)
elif message.type == "image":
return Intent.UNKNOWN # Graceful degradation
else:
text = message.text
return await llm.extract_intent(text)
3. Confirmation is Critical
Never assume. Always confirm:
"I've got you down for a haircut with Tendai on Friday at 2pm. Reply YES to confirm or NO to change."
The Results
- 35% reduction in no-shows (reminders work)
- 90% of bookings happen after business hours
- 3 salons in pilot, expanding to 10
What's Next
Applying these patterns to TaxBot.zw—tax compliance for informal businesses. Same philosophy: meet users where they are.
