How to automate outbound Whatsapp

How to use the API to send whatsapp templates?

Mutations in your CRM or ERP system might lead to the desire to start a conversation with your customers. Like for instance an order status update or a new feature that becomes available.

In those cases you would like your CRM or ERP system to be able to initiate a conversation, or at least send an outbound message over Whatsapp.

Of course you can open the Studio, find or create the contact in the Contacts section and then send the message. But you might want to do this in an automated way, directly from-out your back-office system.

Enabling the REST API

In order to prepare your bot for receiving API requests, like the one for sending the outbound message, you need to enable the REST API as a channel. For this you go to Channels and enable the REST API.

Depending on your subscription levels you might need to order the Whatsapp Broadcasting feature before the REST API can be used for sending Whatsapp messages.

Once enabled you'll find your authorization key and your BOT ID in the page to copy to your clipboard using the clipboard icon.

Whatsapp template messages

In order to initiate a conversation over Whatsapp, Meta wants you to use a Template message. Read about how to manage templates here.

Broadcasting on Whatsapp

Sending Whatsapp template messages using the REST API can be done using the Whatsapp Broadcasting endpoint. This endpoint allows you to send a template to one or more users. It allows you to define the parameter input for the templates on general level or on a per user level or both.

We need a template* to be created in your Whatsapp for business profile in order te test it.

* If you didn't create a template you can always use the botsqd_reengagement template since this is created for you when enabling the Whatsapp channel.

For this example we defined a template that notifies people about their delivery:

For this template we need to provide five parameters. The first four are different per user message, the last one (phone number) is the same for all.

Therefore the first four parameters are templated in the Template -> Components -> Parameters using mustache embeddings, see {{ name }} , {{ date }}, {{ from }}, and {{ to }}

The fifth parameters is not templated but hard coded as "+31367606600".

Now the templated parameters are provided per user under Users -> Params. These params will replace the template parameters of the template just before sending.

Lastly a default value can be provided under Params. In this example only the param Name is configured there having "Customer" as value in case a user doesn't have a name provided.

On a Mac/Linux:

curl -X POST \
https://bsqd.me/api/bot/{{BOTID}}/broadcast/whatsapp-template \
-H 'Content-type: application/json' \
-H 'Authorization: Bearer {{AUTH KEY}}' \
-d '{
      "template":
      {
          "name": "confirm_order_delivery",
          "language": "en",
          "components":
          [
              {
                  "type": "body",
                  "parameters":
                  [
                      {
                          "type": "text",
                          "text": "{{ name }}"
                      },
                      {
                          "type": "text",
                          "text": "{{ date }}"
                      },
                      {
                          "type": "text",
                          "text": "{{ from }}"
                      },
                      {
                          "type": "text",
                          "text": "{{ until }}"
                      },
                      {
                          "type": "text",
                          "text": "+31367606600"
                      }
                  ]
              }
          ]
      },
      "users":
      [
          {
              "user_id": "31xxxxxxxxx",
              "params":
              {
                  "name": "James",
                  "date": "Tuesday 4 May",
                  "from": "09:00",
                  "until": "12:00"
              }
          },
          {
              "user_id": "31xxxxxxxxx",
              "params":
              {
                  "name": "John",
                  "date": "Friday 5 May",
                  "from": "10:00",
                  "until": "13:00"
              }
          }
      ],
      "params":
      {
          "name": "customer"
      }
    }'

The above example will send two Whatsapp template messages. They will be registered in the platform as one single Broadcast item. Using the GET method of the same endpoint the status can be requested.

The response of this method will be something like this:

{
    "broadcast":
    {
        "bot_id": "…",
        "failures":
        [],
        "id": "{{ID}}",
        "statistics":
        {
            "cancelled": null,
            "delivered": null,
            "failed": null,
            "sent": null,
            "total": 2
        },
        "template":
        {
            "components":
            [
                {
                    "parameters":
                    [
                        {
                            "text": "{{ name }}",
                            "type": "text"
                        },
                        {
                            "text": "{{ date }}",
                            "type": "text"
                        },
                        {
                            "text": "{{ from }}",
                            "type": "text"
                        },
                        {
                            "text": "{{ until }}",
                            "type": "text"
                        },
                        {
                            "text": "+31367606600",
                            "type": "text"
                        }
                    ],
                    "type": "body"
                }
            ],
            "language": "en",
            "name": "confirm_order_delivery",
            "namespace": "…"
        }
    }
}

The part where it says {{ID}} holds the identifier to this particular broadcast event. It can be used to query the status of the broadcast. This is is needed because the actual sending of the template messages is done asynchronously by the platform. When it cannot deliver them initially it will schedule a couple of retries.

By using the GET method on the same endpoint the status of the broadcast can be retrieved. Fill in the {{ID}} field with the {{ID}} retrieved out of the response above.

On a Mac/Linux:

curl -X GET \
https://bsqd.me/api/bot/{{BOT ID}}/broadcast/whatsapp-template/{{ID}} \
-H 'Content-type: application/json' \
-H 'Authorization: Bearer {{AUTH KEY}}'

Now you will find that the messages are delivered or not:

       "statistics":
        {
            "cancelled": 0,
            "delivered": 2,
            "failed": 1,
            "sent": 3,
            "total": 3
        },
        "template": {},
        "failures" [
            {
                "reason": "string",
                "details": "string",
                "attempted_at": "string",
                "user_id": "string"
            }
        ]

In the failures element you'll find all the numbers that didn't receive your template with the reason and details.

Changes per version 3.3

Support for URL buttons with param

It was already possible to create templates with URL buttons, where the URL could contain a single variable (ex: "https://example.com/{{1}}"). These were previously not supported in the template broadcast API. They are now. For example:

json
{
  "template": {
    "name": "my-template",
    "language": "en",
    "components": [
      {
        "type": "button",
        "sub_type": "url",
        "index": 0,
        "parameters": [
          {"type": "text", "text": "my-campaign-referrer-link"}
        ]
      }
    ]
  },
  "users": [...]
}

The above will result in "https://example.com/my-campaign-referrer-link" for all of the targeted users.The per-user custom parameters are supported here as well:

json
{
  "template": {
    "name": "my-template",
    "language": "en",
    "components": [
      {
        "type": "button",
        "sub_type": "url",
        "index": 0,
        "parameters": [
          {"type": "text", "text": "{{ user_link }}"}
        ]
      }
    ]
  },
  "users": [
    {"user_id": "31612345678", "params": {"user_link": "first-user"}},
    {"user_id": "31687654321", "params": {"user_link": "second-user"}},
    {"user_id": "31688888888"}},
  ],
  "params": {
    "user_link": "new-user"
  }
}

Which results in "https://example.com/first-user", "https://example.com/second-user", and "https://example.com/new-user" respectively.

Per-user message status

Previously only failures before sending the template were recorded and returned by the API. In the new version of the API we return the status for each targeted user. This also includes delivery failure messages from WhatsApp.The API remains backwards compatible, with two a few additions, and some deprecations:

  • In the broadcast' statistics field, the cancelled field is now deprecated and will always return 0.

  • In the broadcast' statistics field, the pending key has been added.

  • A new field, statuses, has been added which is an array with the per-user status of sending the template.

  • The failures has a new status field, which is always set to failure (see next item).

  • The failures list is now deprecated, as each object in failures has an identical object in statuses.

Refer to the API documentation for more details, such as the possible statuses and errors.## Stricter validationIn the new version of the API the validation of the given template is expanded. Previously only the existence of the template by the given name and language was checked. Now the given components are also matched against the structure of the template.You might see an HTTP 400 response such as:

{
  "error": "The parameters do not match the template.",
  "details": [
    "Missing parameter for header",
    "Missing parameter for body variable {{1}}",
    "Missing parameter for button at index 0, variable {{1}}",
  ]
}

Whatsapp Opt out

By default all contacts are considered to be optin for business initiated conversations (outbound). It is key that you as user of this service acquires optin concent beforehand.

If a contact decides to no longer consent to be optin, he or she can always optout by typing 'optout' and press send. The chat skill is then programmed to store the value "all" in the user variable "whatsapp_optout". This way the system will prevent any outbound initiation message to be send to this content. You can still respond to inbound messages though.

The content the bot will use to reply can be configured in the content section.

Deprecated: send a single Whatsapp template message

This is a deprecated method for sending whatsapp messages. Use the broadcast function instead, see above chapter.

Besides the Broadcast API endpoints, there is another endpoint that can be used. This is the operator action endpoint. Besides relaying operator actions this endpoint can send Whatsapp template messages too.

We can test it using the command line, using the curl command.

* If you didn't create a template you can always use the botsqd_reengagement template since this is created for you when enabling the Whatsapp channel.

On a Mac/Linux:

curl -X POST \
https://bsqd.me/api/bot/{{BOT ID}}/user/whatsapp{{+31…}}/conversation/main/operator-action \
-H 'Content-type: application/json' \
-H 'Authorization: Bearer {{AUTH KEY}}' \
-d '{
  "action": {
    "type": "template",
    "payload": {
      "template_type": "text",
      "template_id": "botsqd_reengagement",
      "parameters": {
        "1": "Niels",
        "2": "Hallo daar!"
      }
    }
  }
}'

You need to replace the {{BOT ID}} and {{AUTH KEY}} placeholders by the values that are provided to you on the REST API Channel page (see above) and the {{+31…}} placeholder by the ISO formatted phone number you would like to send the message to.

The response should look like:

{
    "action":
    {
        "as": null,
        "delay": null,
        "id": "…",
        "payload":
        {
            "parameters":
            {
                "1": "Niels",
                "2": "Hallo daar!"
            },
            "template_id": "botsqd_reengagement",
            "template_type": "text",
            "text": "Niels heeft gereageerd op uw bericht met: Hallo daar!"
        },
        "sender": null,
        "time": "2022-08-24T11:51:11.917567Z",
        "type": "template",
        "visibility": "external"
    },
    "bot_id": "…",
    "channel":
    {
        "type": "whatsapp"
    },
    "conversation_id": "main",
    "event_created": "2022-08-24T11:51:12.694772Z",
    "type": "operator_action",
    "user_id": "31615080195"
}

Language

For some cases you need to fixate the language for the template message to a specific language. In that case you can add the following element to the payload:

"locale_override": "nl"

Now you are ready to implement the same REST call in your software.

Last updated