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 CodeDescription
message.businessPhoneNumberId.invalidThe provided WhatsApp Business phone number ID is invalid or not associated with your account.
destinationNumber.invalidThe destination (recipient) phone number is missing, malformed, or not in international format.
account.waba.missingNo WhatsApp Business Account (WABA) is linked to this request.
account.waba.inactiveThe WABA exists but is inactive or not configured for messaging.
template.notFoundThe specified message template does not exist in your WABA.
template.language.invalidThe language code provided for the template is not valid for this template.
template.invalidThe template structure or name is invalid.
template.button.index.invalidA button index provided does not exist in the template.
template.button.total.invalidToo many buttons were supplied or the count exceeds what the template supports.
template.button.url.invalidA URL button has an invalid or missing URL value.
template.button.couponcode.characterLimitA coupon code is limited to 20 characters.
template.button.couponcode.spacesA coupon code may not contain any spaces.
templateBatch.size.emptyThe batch request contains no messages.
templateBatch.size.exceededThe batch exceeds the maximum allowed number of messages. 1000 is the limit
templateBatch.allMessages.failedValidationEvery message in the batch failed validation (e.g., template, parameters).
engagement.content.emptyThe message body or content is empty for an engagement-type message.
replyRead.wamId.invalidThe provided WhatsApp message ID (wamid) for marking as read is invalid.
server.internal.errorAn unexpected server-side error occurred. Retry the request later.
template.parameters.invalidTemplate parameters provided are invalid or do not match the template structure.
template.header.parameter.type.invalidThe header parameter type (text, media, etc.) does not match the template’s defined header type.
template.button.type.invalidA button parameter type (e.g., URL, quick reply) does not match the template definition.
template.parameters.type.invalidA parameter supplied has the wrong data type for the template.
template.parameters.missingRequired parameters for the template are missing.
template.header.parameter.missingThe template requires a header parameter but none was provided.
template.header.parameter.invalidA provided header parameter is malformed or does not meet template requirements.
template.button.parameters.missingRequired parameters for the template’s button were not supplied.
template.parameters.count.invalidThe number of parameters does not match the template's placeholders.
template.parameters.names.invalidNamed parameters do not match those defined in the template.
request.json.field.invalidThe JSON request contains an invalid or unexpected field.
template.parameters.media.missingThe provided media ID is invalid or does not exist.
template.parameters.media.staleThe referenced media has expired or is no longer available.
media.file.tooLargeThe media file exceeds the maximum allowed file size for the specified type.
media.file.missingNo media file was included in the request.
media.mimeType.unsupportedThe media file type is not supported.
media.mimeType.extensionMismatchThe file extension does not match the detected media type.
rateLimit.exceededToo 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": ""
}

Did this page help you?