Sending a Whatsapp message
WhatsApp API Quickstart -- Send a WhatsApp Message
This guide helps you quickly send your first WhatsApp message using an HTTP API.
Overview
With WhatsApp's Business API, you can send messages programmatically over HTTPS using JSON payloads. You'll need a WhatsApp Business Account (WABA), a phone number attached to it, and an API credentials to authenticate your API calls. The WhatsApp Business API requires a template message to start a conversation; you cannot just start sending free form messages. Once the user replies to your template message, a customer service window (CSW) remains open for 24 hours, which allows free form text messages to be sent.
1. Prerequisites
Before you begin make sure you have gone through our signup and template documents. Here we assume you have signed up and have an approved template that is ready to send.
2. Send a Template Message -- HTTP POST
Endpoint
POST https://rest.smsportal.com/whatsapp/v1/messages/templates
Request Body (JSON)
For a simple template
{
"templateName": "customer_order",
"businessPhoneNumberId": "000000000000000",
"language": "en_US",
"destinationNumber": "27000000001",
"customerId": "1000",
}This assumes you have created a template with the name customer_order that has a language of en_US. A template is specific in a specific language and WhatsApp allows various languages such as en, en_US, en_GB and others.
The CustomerId is an identifier that you supply that we use for tracking your request. You can think of this field as a customer supplied identifier.
The businessPhoneNumberId is an identifier that you receive when you add and verify your number. You can also find this on the Numbers profile page of the specific number you are trying to send with.
3. API responses
After sending a message, you will receive a response which includes a messageId. This is a number that identifies your message within our system for internal tracking purposes. You should store the messageId's that you receive from us with your associated record of the send as status webhooks contain the messageId for correlation; for customer support requests you can provide us with either the messageId or the CustomerId (assuming it is unique) to track a message.
Validation
We perform validation on messages to provide the user with feedback as soon as possible. Our validation is set up to mirror Meta's WhatsApp message validation, however even if it passes our validation, Meta may still reject the message. The main goal of this validation is to ensure you provide the correct parameters for your template.
Webhooks
There is limited feedback that we can provided before a message is sent from within Meta's system. Some errors will only occur once a message has been sent (for example, a number is not registered on whatsapp). This information will be relayed to you via webhooks. It is important to integrate webhooks into your system to receive delivery events, and the final delivery status.
4. Freeform messages
Once you have sent your template message, you will need to wait for the customer to reply, at which time the CSW will open for a 24-hour period for that business number. You can then send a free form message using our API to the customer.
POST https://rest.smsportal.com/whatsapp/v1/messages/engagement
Request Body (JSON)
{
"destinationNumber": "27000000001",
"businessPhoneNumberId": "000000000000000",
"customerId": "1000",
"content": "Thank you for making use of our services. Should you have any further enquiries, please contact our support team at 0820000000"
}5. Error codes
We may reject your request for various reasons. Apart from authentication issues or non-existing resources or other more general issues, below is the list of error codes our API may return for a bad request.
| Error Code | Description |
|---|---|
message.businessPhoneNumberId.invalid | The provided WhatsApp Business phone number ID is invalid or not associated with your account. |
destinationNumber.invalid | The destination (recipient) phone number is missing, malformed, or not in international format. |
account.waba.missing | No WhatsApp Business Account (WABA) is linked to this request. |
account.waba.inactive | The WABA exists but is inactive or not configured for messaging. |
template.notFound | The specified message template does not exist in your WABA. |
template.language.invalid | The language code provided for the template is not valid for this template. |
template.invalid | The template structure or name is invalid. |
template.button.index.invalid | A button index provided does not exist in the template. |
template.button.total.invalid | Too many buttons were supplied or the count exceeds what the template supports. |
template.button.url.invalid | A URL button has an invalid or missing URL value. |
template.button.couponcode.characterLimit | A coupon code is limited to 20 characters. |
template.button.couponcode.spaces | A coupon code may not contain any spaces. |
templateBatch.size.empty | The batch request contains no messages. |
templateBatch.size.exceeded | The batch exceeds the maximum allowed number of messages. 1000 is the limit |
templateBatch.allMessages.failedValidation | Every message in the batch failed validation (e.g., template, parameters). |
engagement.content.empty | The message body or content is empty for an engagement-type message. |
replyRead.wamId.invalid | The provided WhatsApp message ID (wamid) for marking as read is invalid. |
server.internal.error | An unexpected server-side error occurred. Retry the request later. |
template.parameters.invalid | Template parameters provided are invalid or do not match the template structure. |
template.header.parameter.type.invalid | The header parameter type (text, media, etc.) does not match the template’s defined header type. |
template.button.type.invalid | A button parameter type (e.g., URL, quick reply) does not match the template definition. |
template.parameters.type.invalid | A parameter supplied has the wrong data type for the template. |
template.parameters.missing | Required parameters for the template are missing. |
template.header.parameter.missing | The template requires a header parameter but none was provided. |
template.header.parameter.invalid | A provided header parameter is malformed or does not meet template requirements. |
template.button.parameters.missing | Required parameters for the template’s button were not supplied. |
template.parameters.count.invalid | The number of parameters does not match the template's placeholders. |
template.parameters.names.invalid | Named parameters do not match those defined in the template. |
request.json.field.invalid | The JSON request contains an invalid or unexpected field. |
template.parameters.media.missing | The provided media ID is invalid or does not exist. |
template.parameters.media.stale | The referenced media has expired or is no longer available. |
media.file.tooLarge | The media file exceeds the maximum allowed file size for the specified type. |
media.file.missing | No media file was included in the request. |
media.mimeType.unsupported | The media file type is not supported. |
media.mimeType.extensionMismatch | The file extension does not match the detected media type. |
rateLimit.exceeded | Too many requests sent in a short period; rate limit has been exceeded. |
6. Notes & Best Practices
Conversation windows
- Outside of the 24-hour user messaging window, you can only send pre-approved templates - not freeform text. Ensure templates are created and approved first through our WhatsApp template creator.
Rate limiting
Meta uses a two-tier rate limiting system: (1) portfolio-level and (2) per-user. It’s important to understand how portfolio limits can impact message sending, as both the daily and per-second message caps may affect your use case. See messaging limits for more info.
7. Parameters when sending
When sending you can provide header, body and button parameters.
Header parameters
There are 3 types of headers that you can specify when creating your template:
- Text: "Hello dear customer" or "Hello {{firstName}}.
- Media: Image, Document, Gif or Video (see the API reference for more details).
- Location: Lattitude, longitude, name, address (see the API reference for more details).
Body parameters
If your template requires body parameters, you would have defined these parameters as either named or positional. You will need to supply the type that corresponds with your template specification when sending. If you do not, our API will return an error code indicating you supplied incorrect body parameters.
- Positional parameters in your template specification: "Hello {{1}}, your order is ready for collection at our pickup point. Use code {{2}} for collection.".
- Named parameters in your template specification: "Hello {{firstName}}, your order is ready for collection at our pickup point. Use code {{collectionCode}} for collection."
Positional parameters when sending:
{
...
"parameters": {
"body": {
"positional": ["John", "1"]
}
}
}Named parameters when sending:
{
...
"parameters": {
"body": {
"named": { "firstName": "John", "collectionCode": "1" }
}
}
}Button parameters
There are 3 types of button parameters that you are allowed to specify. Templates are allowed a maximum of 10 buttons, although there are limits to specific button types as well. Buttons require an index (starting at 0) that specify which button in the template specification you are referring to.
- CouponCode: CouponCode buttons copy a text string (defined when the template is sent in a template message) to the device’s clipboard when tapped by the app user.
- Url: URL buttons load the specified URL in the device’s default web browser when tapped by the app user. Templates are limited to two URL buttons.
- Otp: One-time password buttons are a special type of URL button component used with authentication templates. Meta handles all authentication buttons as URL buttons, so the code goes in "url", not "otp".
- QuickReplyPayload: An optional additional field that will be returned in the webhook if the WhatsApp user clicks the quick reply button
Footers
Footers do not allow parameters, so you will not be able to provide parameters for your template footer when sending.
8. Full sending flow
The following example is for a template that contains two positional parameters in the body and a single URL button that requires a parameter.
For the credentials base64("API_KEY:API_SECRET")=QVBJX0tFWTpBUElfU0VDUkVUCg==
curl --request POST \
--url https://rest.smsportal.com/whatsapp/v1/messages/templates \
--header 'authorization: Basic QVBJX0tFWTpBUElfU0VDUkVUCg==' \
--header 'content-type: application/json' \
--data '{
"templateName": "order_template",
"businessPhoneNumberId": "000000000000000",
"language": "en_US",
"destinationNumber": "27000000001",
"customerId": "1000",
"parameters": {
"body": {
"positional": [
"John",
"#12345"
]
},
"buttons": [
{
"buttonIndex": 0,
"url": "https://smsportal.com/?invoice=12345"
}
]
}
}'The response (200)
{
"templateName": "order_template",
"businessPhoneNumberId": "000000000000000",
"destinationNumber": "27000000001",
"customerId": "1000",
"messageId": 2304008,
"errorCode": "",
"errorDetail": ""
}After the user responds to our template, we can send a free form message to that user
curl --request POST \
--url https://rest.smsportal.com/whatsapp/v1/messages/engagement \
--header 'authorization: Basic QVBJX0tFWTpBUElfU0VDUkVUCg==' \
--header 'content-type: application/json' \
--data '{
"destinationNumber": "27000000001",
"businessPhoneNumberId": "000000000000000",
"customerId": "1001",
"content": "Thank you for ordering with us."
}'The response (200)
{
"businessPhoneNumberId": "000000000000000",
"destinationNumber": "27000000001",
"customerId": "1001",
"messageId": 2304009,
"errorCode": "",
"errorDetail": ""
}Updated 1 day ago
