@todoforai/whatsapp-api
v1.0.0
Published
JSON-first CLI for the WhatsApp Business Platform Cloud API (messages, templates, media, phone numbers, WABA, flows) on the Meta Graph API, generated from the official OpenAPI spec
Readme
WhatsApp CLI
whatsapp-api is a JSON-first CLI for the WhatsApp Business Platform (Cloud API). It calls the Meta Graph API at https://graph.facebook.com/<version>. The commands are generated from Meta's official OpenAPI spec (facebook/openapi, business-messaging-api_v23.0.yaml, 111 operations). Each command's --help links its doc page. This is not an official Meta tool.
Run locally
cd api-apps/whatsapp-api
npm install --workspaces=false
bun run build
node dist/index.js --helpAuthentication
Every call sends Authorization: Bearer <token>. You can use either of these tokens:
- A system-user access token: Business Settings → System users → Generate token, with scopes
whatsapp_business_messagingandwhatsapp_business_management. It can be made non-expiring. - The temporary 24h token from your app's WhatsApp → API Setup page. That page also shows a free test phone number.
See Access tokens.
<secret-manager-command> | whatsapp-api auth --token-stdin # verified with GET /debug_token, never printed
whatsapp-api whoami # type, app, expiry, scopesYou can also use environment variables:
WHATSAPP_ACCESS_TOKENtakes precedence over~/.config/whatsapp-api/credentials.json(0600).WHATSAPP_API_VERSIONsets the Graph version (defaultv23.0).
You'll need two IDs, both shown on the API Setup page:
<Phone-Number-ID>is the sending number.<WABA-ID>is the WhatsApp Business Account.
Coverage
Commands are named <Graph node> <operationId>:
phone: Phone-Number-ID routes.waba: WABA routes.- Other nodes:
media,template,flow,group,business,app,solution,preverified,profile,user.
Path IDs are arguments, and body field names match the API. Every read accepts --fields (Graph field selection). --all follows paging.cursors.after.
The following are not wrapped:
- Inbound webhooks.
- Multipart media upload. Send media by public
linkinstead, or upload with another client. - Binary download from the signed media URL (
media retrieve-media-urlreturns the URL).
Examples
whatsapp-api phone send-message <Phone-Number-ID> --yes \
--data '{"messaging_product":"whatsapp","to":"36301234567","type":"text","text":{"body":"Hi"}}'
whatsapp-api phone send-message <Phone-Number-ID> --yes \
--data '{"messaging_product":"whatsapp","to":"36301234567","type":"template","template":{"name":"hello_world","language":{"code":"en_US"}}}'
whatsapp-api phone send-message <Phone-Number-ID> --yes \
--data '{"messaging_product":"whatsapp","to":"36301234567","type":"audio","audio":{"link":"https://example.com/voice.ogg"}}'
whatsapp-api waba list-templates <WABA-ID> --fields name,status,language --all
whatsapp-api waba get-whatsapp-business-account-phone-numbers <WABA-ID>
whatsapp-api media retrieve-media-url <Media-ID>
whatsapp-api media delete-media <Media-ID> --yes
whatsapp-api api GET /<Phone-Number-ID> --param fields=display_phone_number,verified_nameWrites need --yes. Use --dry-run to preview the request without credentials or network. API and runtime errors are printed as JSON on stderr (including the Graph error object) and the CLI exits with code 1.
Development
python3 scripts/generate.py # refresh src/endpoints.json from the official spec (needs pyyaml)
bun test
bun run test:node