Run WhatsApp Business API from Claude Code — in plain English.
By Amit Agrawal (@amitpagrawal) — co-founder & CTO, sRide.
$ claude
> /whatsapp-create festive discount promo
? Category? MARKETING
? Body text? Hi {{1}}, enjoy 20% off ...
? Image header? /tmp/diwali.png
? Buttons? [Apply now] [Not now]
? Submit to Meta? Yes
Polling approval (up to 30m, every 60s)...
[0m] status=PENDING
[2m] status=APPROVED
✓ Approved: mkt_festive_promo_v1
> /whatsapp-send alice mkt_festive_promo_v1
Alice Anderson (14155551234) status=accepted id=wamid.xxx
That's the entire workflow. No Graph API docs, no Postman, no BSP.
Meta's WhatsApp Cloud API is powerful but the developer experience is painful:
- Template creation requires hand-crafted JSON with rigid component rules
- Approvals take minutes to days, and the docs don't tell you why things get rejected (no emojis in headers, only
https://URL schemes, etc.) - Sending a test message means remembering phone number IDs and message payload shapes
- Most teams end up paying a BSP (Gupshup, Twilio, Infobip) just to avoid the above
wacli + Claude Code skills = natural-language ops over the raw Cloud API.
- 🐚 CLI-first. Single
wacli.pyfile.stdlib + requests. No BSP, no lock-in. - 🧠 Claude-native. Ships with 5 slash commands for Claude Code. Type
/whatsapp-create welcome message→ Claude handles the wizard. - ⏱ Approval polling built-in.
--wait 30streams status ticks until APPROVED / REJECTED. - 📇 Recipient aliases. Send by name/alias via
recipients.json./whatsapp-send alice welcomejust works. - 🛡 Knows the gotchas. The Claude commands bake in Meta's rejection rules so you don't learn them the hard way.
git clone https://github.com/sridecarpool/wacli
cd wacli
cp .env.example .env # fill in META_WHATSAPP_TOKEN, WABA_ID, PHONE_ID
cp recipients.example.json recipients.json # add your contacts
python3 wacli.py token-check
python3 wacli.py templatesTo use the Claude Code skills, copy .claude/commands/whatsapp-*.md into your project's .claude/commands/ directory (or symlink). Then run claude and try /whatsapp-templates.
| Command | Purpose |
|---|---|
templates |
List + filter by status / category |
matrix |
Template × language × status grid |
template <name> |
Detail view |
send <recipient> <template> |
Single send (phone / alias / name substring) |
test <template> --to a b c |
Multi-send |
create / create-image |
Submit template; --wait N polls in-place |
delete / insights / phone / token-check / recipients |
Housekeeping + diagnostics |
Every subcommand is a thin wrapper around a single Graph API endpoint — no hidden magic.
| Command | What it does |
|---|---|
/whatsapp-send |
NL send: /whatsapp-send alice bob welcome_v1 |
/whatsapp-templates |
List / matrix / detail — smart routing from one input |
/whatsapp-create |
The crown jewel. Auto-detects one-shot vs interactive wizard. Bakes in the Meta gotchas. |
/whatsapp-delete |
Preview + usage warning + confirm |
/whatsapp-status |
Phone + token + template health dashboard |
wacli |
pywa / heyoo |
Gupshup / Twilio / Wati | |
|---|---|---|---|
| Install | git clone |
pip install |
Sign-up + KYC |
| Shape | CLI + Claude skills | Python SDK | Managed service |
| Natural-language ops | ✅ via Claude Code | ❌ | ❌ |
| Template approval polling | ✅ built-in | ⚠ DIY | ✅ via dashboard |
| Recipient aliases | ✅ recipients.json |
❌ | ✅ contacts UI |
| Cost | Meta's own pricing | Meta's own pricing | BSP markup on top |
| Lock-in | None | None | ⚠ BSP-specific APIs |
When to pick wacli: you want to send WhatsApp messages from your terminal, scripts, or Claude Code agents, directly against Meta's Cloud API, without paying a BSP.
When to pick something else: if you need managed conversation threading / agent-assist / a web dashboard for non-devs, a BSP (Wati, Gupshup) is a better fit.
python3 wacli.py create auth_otp_v1 \
--body "{{1}} is your verification code. Don't share it." \
--category AUTHENTICATION \
--example 123456 \
--wait 30python3 wacli.py send alice order_shipped \
--params "Alice" "45678" \
--button-param "45678"python3 wacli.py test maintenance_notice_v1 --to alice bob oncallpython3 wacli.py phone
python3 wacli.py token-check- No emojis in template HEADERS. Meta rejects. Body is fine.
- URL buttons must be
http(s)://. Custom schemes likemyapp://get rejected. - New numbers silent-drop MARKETING until the display-name review completes. Utility + free-form text land fine.
- Default business profile (
"Hey there! I am using WhatsApp.") is a spam signal. Set a proper about/description/website. - Template approval is usually under 5 minutes for text templates, sometimes near-instant.
--wait 30covers it. - Phone migration between WABAs needs a deregister + re-add. Can't do it purely via API across different Business Managers.
More in docs/gotchas.md (coming soon — contributions welcome).
- PyPI package:
pip install wacli - Webhook receiver for delivery-status tracking
- Interactive
wacli initfor first-time setup - Demo GIF in README
- Node.js / TypeScript port of the Claude commands
See CONTRIBUTING.md. Keep wacli.py a single-file, stdlib + requests tool. New Claude commands welcome.
MIT — see LICENSE.
Built and maintained by Amit Agrawal — co-founder & CTO at sRide.
If wacli saves you a day, a star is the cheapest thank-you ⭐. Issues, PRs, and DMs all get answered.
Born from sRide's migration off a BSP to direct Meta Cloud API in an afternoon. If you're stuck on the same migration — open an issue, I've already debugged the gotchas.