Send WhatsApp API messages by posting JSON to the business phone number’s versioned /messages endpoint, then follow the returned message ID through status webhooks. Use 5 checks: permission, message route, submission, outcome and escalation. A successful response confirms acceptance, not delivery. The example below is an illustrative service reply, not an executed send.
What should happen before an API message is submitted?
Record the purpose and permission before constructing a request. The WhatsApp Business Messaging Policy requires the recipient to have provided their number or username and given opt-in permission. A number copied from an invoice is not an unrestricted messaging instruction. Retain the permission reference and respect subsequent opt-outs, including requests made outside WhatsApp.
Choose the message route at sending time. Meta’s service-message guide describes a customer-service window opened by an incoming message or call, with the timer resetting on another qualifying interaction. Service replies belong inside that window; outside it, use an appropriate pre-approved template. A queued reply can become unsuitable while waiting. Template approval also does not authorise unrelated content or replace recipient permission.
Prepare the account and sender
Meta’s getting-started guide starts with a Facebook or managed Meta account, developer registration and a WhatsApp-enabled test device. Its documented setup creates a Meta app with the WhatsApp use case, selects a business portfolio and connects a Messaging account in API Setup. The sender’s phone number ID identifies the API resource; it is not the recipient’s number. Keep the account and sender references distinguishable.
The guide provides a temporary test-token route and a separate system-user token setup. Keep tokens server-side and outside public source files, screenshots and enquiry forms. The permissions reference identifies whatsapp_business_messaging for sending and incoming/status webhooks. Account-management operations have their own requirements. Configure only the permissions and asset access needed for the actual integration; another account’s connection or a sample dashboard does not establish your app’s authority.
Construct a bounded text request
For a permitted individual service reply, the Messages API reference specifies POST on the versioned business-phone-number messages resource with bearer authentication. This original example adapts the documented text-message structure. Every uppercase identifier is a placeholder; it is not a runnable account configuration.
POST https://graph.facebook.com/API_VERSION/BUSINESS_PHONE_NUMBER_ID/messages
Authorization: Bearer ACCESS_TOKEN_PLACEHOLDER
Content-Type: application/json
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "RECIPIENT_NUMBER_WITH_COUNTRY_CODE",
"type": "text",
"text": {
"body": "Thanks for your question. Your reference is EXAMPLE-ORDER."
}
}
Use the API version selected for the implementation and the authorised sender ID. Replace the recipient placeholder only in an authorised test environment. Meta recommends including the plus sign and country calling code; omitting them can route a number incorrectly. The type value selects the message format, and the matching text object carries its contents. Do not insert a template name into this service-text payload and assume it becomes a template request.
The guide also describes an account-selection condition: if the token has messaging access to multiple Messaging accounts on that sender, include the applicable messaging_account_id. If it has access to exactly one, omit that property and Meta resolves it. Establish which case applies rather than guessing an account identifier.
How do you interpret the response and handle exceptions?
The service guide’s successful-response structure includes the messaging product, contact identifiers and a messages array. A shortened illustrative response would have this shape; these placeholder values were not returned by a live request:
{
"messaging_product": "whatsapp",
"contacts": [
{"input": "RECIPIENT_NUMBER", "wa_id": "RECIPIENT_ID"}
],
"messages": [
{"id": "MESSAGE_ID"}
]
}
Store the returned message ID against the business action. The submitted contact value and returned WhatsApp identifier need not be identical, so do not infer their interchangeability. Most importantly, this response means the request was accepted. It does not establish that a handset received the message or that a person read it.
Subscribe to the documented messages webhook topic and configure an authorised endpoint to receive status notifications. Meta’s status reference supplies the message ID, status and event timestamp within the statuses array. Match that ID to the submission record instead of changing every message for the same order.
| Evidence received | Documented meaning | Ledger action |
|---|---|---|
| Successful send response | Request accepted | Save message ID; await outcome |
sent webhook |
Sent from Meta’s servers | Record server-send state |
delivered webhook |
Delivered to the user’s device | Record device delivery |
read webhook |
Displayed in an open chat thread | Record the documented read signal |
failed webhook |
Failure to send or deliver | Retain error details and assign investigation |
Do not require an uninterrupted sequence of separate webhook events. The reference explains that a read event can imply delivery and the separate delivered webhook may be omitted. Nor does a read signal prove comprehension, agreement or completion of the underlying business task. Keep those outcomes separate.
Treat a lost HTTP response as ambiguous. The provider may have received the request even though the application did not retain its answer. Use a stable business-action reference and a reconciliation process before retrying; this article does not claim undocumented provider deduplication. For an actual failure, inspect the documented error information before deciding whether correction or retry is appropriate.
Original contribution: message-state decision ledger
Create a fictional EXAMPLE-ORDER record with purpose, permission reference, latest inbound event, selected route, business-action reference, provider message ID, observed status, event time and next owner. Work through a customer withdrawing permission while the message is queued: the correct decision is suppression before submission. Repeat with permission intact but the service window closed: reconsider the route rather than sending the same text request.
Then simulate an accepted response with no observed delivery status, followed by a read event without a separate delivered event. The first remains unresolved; the second follows Meta’s documented delivery implication. Record expected decisions as proposed checks until an authorised implementation actually demonstrates them. This makes the worksheet useful without inventing test results.
Finally, give automated conversations a real escalation route. The policy requires prompt, clear and direct escalation paths when automation is used in the service window. Name only a route the business operates, assign unanswered handovers and preserve opt-outs across the queue. A message submission is not a completed customer conversation.
See WhatsApp Business for channel context and web development for integration scope. To discuss requirements, get started with fictional examples and the ledger. Keep credentials, customer lists and private conversations out of the enquiry.
By Spout Team. AI-assisted drafting by Codex using the linked primary sources.