Send messages
POST to Meta Graph API v24.0 with a Bearer token. Same shape for the sandbox through the proxy and your own number direct.
The basic call
Every send is a POST to ${WHATSAPP_API_URL}/${WHATSAPP_PHONE_NUMBER_ID}/messages with Authorization: Bearer ${WHATSAPP_ACCESS_TOKEN} and a JSON body whose first key is messaging_product: "whatsapp".
The shape is identical for the sandbox (through the HookMyApp proxy) and your own number (direct to Meta). Only the base-URL variable differs: the sandbox env sets WHATSAPP_API_URL, while your own number's env sets META_GRAPH_API_URL. The Node example below reads whichever is present (WHATSAPP_API_URL ?? META_GRAPH_API_URL); the curl example uses whichever your env has. For the full message-object reference see Meta's Cloud API docs.
curl example
Node/Express example
Verbatim from the webhook starter kit (src/providers/whatsapp.js). It reads whichever base-URL variable your env has, so the same code runs against the sandbox and your own number.
Templates need your own number
Sandbox blocks template sends.
The sandbox proxy rejects
type: "template"messages. Test templates against a connected WhatsApp number, not the sandbox.
Rate limits and retries
Meta enforces per-phone messaging tiers and per-account business-initiated-conversation quotas. HookMyApp passes rate-limit error responses through untouched so your retry logic sees them directly.
For current tier thresholds, pair rates, and the 429 retry contract, see Meta's rate-limit docs.
Next steps
- Receive Webhooks: Handle the delivery and read receipts.
- Sandbox: Try the send flow end-to-end with a test number.