Status: In Development · Playground demo coming soon.
The recipe below is complete and runnable today; only the hosted playground showcase is pending.
What you’ll build
A single-WABA inbound agent that:- Takes inbound WhatsApp messages and replies in-thread
- Detects handoff signals: sentiment, keywords, explicit asks, repeat failure
- Hands off to a human by surfacing the conversation in your agent console / Slack with full memory context
- Goes quiet while the human owns the thread
- Resumes when the human releases: full context, no recap
When to use this recipe
Build this if:- You have one WABA number for one product or business line
- You have human agents available some of the time but want AI coverage the rest
- The handoff in and out has to feel seamless to the customer
- You’re okay with conversation continuity tied to phone number (which it is on WhatsApp)
Architecture at a glance
The “handoff state” is a single key per customer (AI_HANDOFF[phone]). When set, the AI agent stops responding. Human turns are still ingested into Synap so the AI has them when it resumes.
Stack
Prerequisites
- A Synap API key. See Authentication
- A WABA number, Meta Business app, verified, with a webhook configured to point at your backend
- A System User access token with
whatsapp_business_messagingscope - A human console / Slack channel for handoffs
- Python: Python 3.11+
- TypeScript: Node 18+ and Python 3.11+ on the host
Install
Configure
Build it
1. Identity & scoping
WhatsApp gives you a stable identifier: the customer’s phone number. Use it asuser_id.
customer_id = "<your-business>": your business, single tenantuser_id = <E.164 phone, hashed if you prefer>conversation_id = <one per phone>: WhatsApp doesn’t have explicit sessions; treat the whole relationship as one rolling conversation
conversation_id, user_id, and customer_id must be valid UUIDs. Since these key off the phone, derive a deterministic UUID from it with uuid.uuid5(...) (Python) rather than passing the raw phone string.If your privacy posture requires it, hash phone numbers (e.g.,
sha256("e164:" + phone)) before using them as user_id. Synap will treat the hash as the stable identifier; you keep raw phones in your own DB.2. Handoff state
3. The handoff tool
The agent decides when to hand off. The tool fans out: persist a structured memory record + notify the human console.4. The inbound webhook
WhatsApp webhooks deliver inbound messages. Return 200 fast, process async.5. The AI agent
6. The human side
Two affordances in your console / Slack:- Reply to the customer → posts a message via WABA, ingests it into memory tagged
tier: "human". - Release the thread → calls
end_handoff(phone). Next customer message routes to the AI again, with full handoff history loaded from memory.
Run & verify
Next day, new message
Customize / extend
- Multiple WABA numbers → see Multi-WABA Shared Memory for the routing pattern.
- Outbound campaigns + inbound → see Single-WABA Campaign + Inbound.
- Slack as the human console → post handoff alerts into a
#wa-supportchannel; replies posted in-thread relay back via WABA. Same pattern as Patterns → Slack Bot. - Auto-release on inactivity → after N minutes of no human reply, clear
AI_HANDOFFautomatically (Redis TTL). - Tier-escalation flavor → for AI→AI handoff instead of AI→human, see Tier-1 → Tier-2 Escalation.
Troubleshooting
AI replies during a human handoff- Race condition: webhook fired before
AI_HANDOFFwas set. Checkis_handoffinside the async task, not in the webhook handler.
- Confirm human turns are being ingested into memory with
tier: "human"metadata. If they’re missing, the AI sees a gap and may re-ask basic questions.
- WhatsApp expects a 200 within 20s. Return immediately from the route handler and run
handleInboundin the background. Don’tawaitit.
- WhatsApp redelivers webhooks that don’t 200 fast enough. Idempotency: track
message_idin Redis with a short TTL and skip duplicates.
- WhatsApp’s 24-hour rule: outside the customer-initiated session window, you can only send approved template messages. Track session start in Redis; refuse to send free-form replies outside the window.
Related
- Integrations: OpenAI Agents SDK · Vercel AI SDK
- Concepts: Memory Scopes · Customer Context · Agent Interactions
- Patterns: Slack Bot · Graceful Degradation · Multi-Tenant SaaS
- Other recipes: WhatsApp Campaign + Inbound · Multi-WABA Shared Memory · Tier Escalation