Channels
WhatsApp Business
Send and receive WhatsApp messages from your own WhatsApp Business Platform number, including templates and interactive messages.
Requirements#
- A Meta Business portfolio with a WhatsApp Business Account (WABA).
- A Facebook login with admin access to that portfolio, and a phone number that can receive a verification code by SMS or call.
- Only for the credential path: a number already registered on the WhatsApp Business Platform (Cloud API) and a system user access token that does not expire, with the
whatsapp_business_messagingandwhatsapp_business_managementpermissions. - At least one approved message template if you intend to start conversations.
Connect the channel#
Continue with Facebook (recommended)#
In the console, open Channels, choose WhatsApp Business and continue with Facebook. A Meta window opens (Embedded Signup): choose or create the WhatsApp Business account, pick or add the phone number and verify it. When the window closes the number is connected; it shows as pending for a moment and then as connected. The identifier is the phone number.
- You can optionally choose a data storage region for the number before you start.
- Nothing has to be copied: no IDs and no tokens.
- This path needs a person at a browser, so it is not available with an API key.
With credentials#
For a number that is already on the Cloud API, choose "Enter credentials manually" in the console, or post the credentials to POST /v1/channels with type: "whatsapp". The identifier is the phone number in E.164 format.
| Field | Where to find it |
|---|---|
wab_account_id | WhatsApp Business Account ID, shown in WhatsApp Manager and in the API setup page of your Meta app. |
phone_number_id | Phone number ID of the sender. It is an ID assigned by Meta, not the phone number itself. |
access_token | System user access token, created under Business settings, System users. |
data_localization_region | Optional. Two-letter region in which Meta stores message data at rest: AU, ID, IN, JP, SG, KR, DE, CH, GB, BR, BH, ZA, AE or CA. |
curl https://api.omnimessage.co/v1/channels \
-H "Authorization: Bearer om_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "whatsapp",
"name": "Support line",
"identifier": "+971800123456",
"credentials": {
"wab_account_id": "104857600123456",
"phone_number_id": "209715200654321",
"access_token": "EAAG..."
}
}'Recipients#
to is the phone number of the recipient in E.164 format: a plus sign, the country code and the number, without spaces, for example +971501234567. The recipient must have a WhatsApp account and must have opted in to hear from your business, as WhatsApp policy requires.
Supported message types#
| Type | Use it for |
|---|---|
text | Plain text of up to 4096 characters. |
attachments | One image, video, document, audio file, voice note or sticker, fetched from an HTTPS URL. |
template | A pre-approved template, required outside the 24-hour customer service window. |
button | Text with one to three quick-reply buttons. |
list | A menu of rows grouped into sections, opened by one button. |
cta_url | Text with one button that opens a URL. |
location | A map pin with a name and an address. |
contacts | One or more contact cards. |
This channel also accepts the pass-through types flow, product, product_list, catalog, carousel, location_request. Their content is forwarded in the provider format without validation: see Channel-specific types.
Channel rules#
The 24-hour customer service window#
WhatsApp lets a business send free-form content (text, media, buttons, lists and so on) only within 24 hours of the last message the user sent to it. Each inbound message restarts the window.
| Situation | What you can send |
|---|---|
| Within 24 hours of the last inbound message from the user | Any supported message type. |
| Outside the window, or the user has never written to you | Only template messages. |
A free-form message sent outside the window is refused by WhatsApp. Depending on when the refusal is reported, the request fails with 422 policy_violation or the message is accepted and then moves to failed with a provider_error. In both cases you are not charged. Track the time of the last message.received event per recipient to know whether the window is open.
Templates#
Templates are created and submitted for approval in WhatsApp Manager. Only templates with status APPROVED can be sent. List the templates of a channel, with their languages and components, through the API:
curl https://api.omnimessage.co/v1/channels/ch_7Hq2mN5vB8cX1zL0pK3j/templates \
-H "Authorization: Bearer om_live_xxxxxxxxxxxxxxxxxxxxxxxx"{
"object": "list",
"data": [
{
"id": "1203948571029384",
"name": "order_shipped",
"language": "en",
"category": "UTILITY",
"status": "APPROVED",
"components": [
{
"type": "BODY",
"text": "Hi {{1}}, your order {{2}} has shipped."
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "URL",
"text": "Track order",
"url": "https://example.com/track/{{1}}"
}
]
}
],
"variables": {
"header": [],
"body": [
{
"key": "1",
"example": null
},
{
"key": "2",
"example": null
}
],
"buttons": [
{
"index": 0,
"type": "url",
"variables": [
{
"key": "1",
"example": null
}
]
}
],
"count": 3
}
}
],
"has_more": false,
"next_cursor": null
}To send one, reference it by name and language.code and fill its variables through components, in the order they appear in the template. The components array follows the WhatsApp Cloud API format and is forwarded unchanged.
curl https://api.omnimessage.co/v1/messages \
-H "Authorization: Bearer om_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"channel": "ch_7Hq2mN5vB8cX1zL0pK3j",
"to": "+971501234567",
"type": "template",
"template": {
"name": "order_shipped",
"language": {
"code": "en"
},
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Layla"
},
{
"type": "text",
"text": "#1042"
}
]
}
]
}
}'Interactive messages#
buttoncarries one to three reply buttons with titles of up to 20 characters.listopens a menu of rows; the label of the opening button is limited to 20 characters.cta_urlshows one button that opens a URL.- A tap on a button or a list row arrives as a
message.receivedevent carrying theidyou assigned.
Fees charged by Meta#
Meta bills WhatsApp usage to the payment method on your WhatsApp Business Account. Those charges are separate from the OmniMessage per-message price.
Example request#
curl https://api.omnimessage.co/v1/messages \
-H "Authorization: Bearer om_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"channel": "ch_7Hq2mN5vB8cX1zL0pK3j",
"to": "+971501234567",
"type": "button",
"button": {
"body": {
"text": "Your delivery is scheduled for tomorrow, 10:00-12:00. Does that work?"
},
"footer": {
"text": "Order #1042"
},
"action": {
"buttons": [
{
"reply": {
"id": "confirm",
"title": "Confirm"
}
},
{
"reply": {
"id": "reschedule",
"title": "Reschedule"
}
}
]
}
}
}'Delivery statuses#
WhatsApp reports sent, delivered and read. Read receipts arrive only if the recipient has them enabled. When a message fails, error.provider_code contains the WhatsApp error code, for example 131026 when the recipient cannot receive the message.
Pricing#
Each accepted outbound message on a whatsapp channel consumes one package credit or the whatsapp price from the wallet. Read your effective price from GET /v1/pricing. Inbound messages are free. Fees charged by the provider are separate. See Billing.