NAV
JSON cURL Python PHP C#

Introduction


                .' '.            __
       .        .   .           (__\_
        .         .         . -{{_(|8)
          ' .  . ' ' .  . '     (__/

Welcome to the Sendbee REST API documentation.
Use our APIs to seamlessly integrate Sendbee functionalities into your website or application.

Client libraries

Sendbee has official libraries that are available in several languages:

Supported channels

WhatsApp Business

You can send and receive WhatsApp messages for customer support, alerts and notifications. Currently you don’t need to specify WhatsApp channel as a destination when making Sendbee API calls, as it’s the only channel we support.

WhatsApp Opt-In Requirements

WhatsApp requires that a contact must first consent to receive messages in WhatsApp by opting into them via a third-party channel. This can be any channel your business uses to communicate with people today — your website, app, email, SMS, retail location, etc. Sending users messages without an opt-in may result in users blocking your business and suspension of your WhatsApp business account.

To learn more, please visit WhatsApp Business API guide

WhatsApp consent

Notifications (Message Templates)

WhatsApp requires that any initiated messages sent by your business must be a pre-approved templated message. These messages are called Message Templates, with the exception of messages sent as a reply to a contact-initiated message (see the Customer Care Messages section below for more details). Currently only text messages can be sent as Message Templates.

To learn more, please visit our guide for sending WhatsApp notifications using message templates.

Customer Care Messages

To have a 2-way conversation with a contact, you need to receive messages from them. Contacts can send you a message in response to a Message Template or directly via WhatsApp click-to-chat link (see WhatsApp click-to-chat link section below).

WhatsApp 24-hour customer care window

A WhatsApp 24-hour customer care window begins when a contact-initiated message was sent to your business. Sessions are valid for 24 hours after the most recently received message, during which time you can communicate with contacts using free form messages. These messages are called Customer Care Messages. In order to send a message outside the 24-hour custom care window, you must use a pre-approved Message Template (see the Notifications section above for more details).

WhatsApp’s click to chat feature allows your customers to begin a chat with your business on WhatsApp without having your phone number saved in their phone’s address book. By clicking the link, a chat with your business automatically opens. Click to chat link works on WhatsApp mobile apps and WhatsApp Web.

To create your link use https://wa.me/ where the is a full phone number in international format. Omit any zeroes, brackets, or dashes when adding the phone number in international format.

Examples:
Use: https://wa.me/15551234567
Don’t use: https://wa.me/+001-(555)1234567–

To learn more, please visit WhatsApp click to chat link guide.

How to make a request

Every request to the API should be made with the following data in headers:

{
    "X-Auth-Token": "...",
    "X-Api-Key": "...",
    "Accept": "application/json",
    "Content-Type": "application/json"
}

In order to use Sendbee APIs, you need to have an active Sendbee business account. Create your account at www.sendbee.io.

Base API URL is https://api-v2.sendbee.io

To authenticate a request to the API, you must create an Auth token as described in Authentication section and send it in authorization header using X-Auth-Token key. Also, API key should be added in header mapped with X-Api-Key key.

Request header name Request header value
X-Api-Key Your API key (available in Sendbee dashboard)
X-Auth-Token Generated auth token. See Authentication for information on how to generate auth tokens.
Accept application/json
Content-Type application/json

Response

The response may contain data, meta, links, warning or error elements.

Response with pagination elements

Response with pagination elements:

{
    "data": {...},
    "meta": {
        "current_page": ...,
        "from": ...,
        "to": ...,
        "total": ...,
        "per_page": ...,
        "last_page": ...
    },
    "links": {
        "first": "...",
        "last": "...",
        "next": "...",
        "prev": "..."
    }
}

When you’re making calls to the Sendbee API, in some cases API endpoints could return a list of data consisting of a larger amount of elements. For that reason, we paginate the results to make sure responses are easier to handle. Paginated responses are usually returned when making GET or any other request that returns a list of data in the response. The paginated response contains data, meta and links elements.

Response without pagination elements

Response without pagination elements:

{
    "data": {...}
}

Responses without pagination are usually returned when making POST, PUT, DELETE or any other request that doesn’t return a list of data in the response. The unpaginated response contains only a data element.

Warnings

Warning in response:

{
    "warning": "...",
    "data": {...},
    ...
}

If something goes wrong in an API request, an error or a warning will be returned. Warnings are usually returned for non-fatal conditions indicating the issues that should be addressed, whereas errors are only returned for fatal conditions.

Errors

Error in response:

{
    "error": {
        "detail": "...",
        "type": "..."
    }
}

In case of an error, the response will not contain any other data then the error data. Errors usually occur when a parameter is missing, is invalid or when you try to update a contact using a contact ID that doesn’t exist.

Authentication


import hmac, base64, hashlib
from datetime import datetime, timezone

API_SECRET = '...'

# step 1: get current timestamp
timestamp = str(int(
    datetime.now(timezone.utc).timestamp()
)).encode('utf-8')

# step 2: encrypt timestamp with your API secret to get a hash
encrypted = hmac.new(
    API_SECRET, data, hashlib.sha256
).hexdigest()

# step 3: concatenate timestamp and hash
timestamp_encrypt = '{}.{}'.format(
    timestamp.decode("utf-8"), encrypted.decode("utf-8")
).encode('utf-8')

# step 5: translate concatenated string into base64
auth_token = base64.b64encode(ts_encrypt).decode("utf-8")
<?php
// your API secret
$API_SECRET = '...';


// preferred method: using PHP API
$requestIsValid = \Sendbee\Api\Client::generateToken($API_SECRET);



// manual method (if you don't want to use the PHP API library)

// step 1: get current timestamp
$timestamp = time();

// step 2: encrypt timestamp with your API secret
$hashedData = hash_hmac('sha256', $timestamp, $API_SECRET, false);

// step 3: concatenate timestamp and encrypted_b64
$timestamp_encrypt = $timestamp . '.' . $encryptedData;

// step 4: translate concatenated string into base64
$auth_token = base64_encode($timestamp_encrypt);

?>
using System;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(getAuthKey());
    }

    public static string getAuthKey()
    {
        string API_SECRET = "...";

        Int32 timestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
        string hashedData = HashHmac(timestamp, apiSecret);

        return Base64Encode(timestamp + "." + hashedData);
    }

    private static string HashHmac(string data, string key)
    {
        using (HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(key)))
        {
            string a2 = hmac.ComputeHash(Encoding.ASCII.GetBytes(data));
            return a2;
        }
    }

    public static string Base64Encode(string plainText)
    {
        var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
        return System.Convert.ToBase64String(plainTextBytes);
    }
}

Every request to the API should be made with the following data in headers:

{
    "X-Auth-Token": "...",
    "X-Api-Key": "...",
    "Accept": "application/json",
    "Content-Type": "application/json"
}

The Sendbee API uses the Auth token to authenticate requests.
To create an Auth token for every request, you need API Secret.

Follow these steps to create an authentication token:

1. get current timestamp (in seconds)
2. encrypt the timestamp with your API secret key using HMAC sha256 encrypt algorithm (the output should be lowercase hexadecimal)
3. concatenate timestamp and encrypted timestamp separated by a . (dot)
4. translate the concatenated string into base64

Check out official Sendbee API client libraries.
If you are using some of those languages it is highly recommended to use our client library because in that case you don’t need to worry about authentication, the library does it for you.

If you’re using programing language other then the ones we provide client libraries for, please consider using these examples on how to create a valid auth token:

Step-by-step tutorial

If you’re having trouble writing code that successfully generates an authentication token, please try following this step-by-step tutorial and test your code.
For this tutorial we will be using predefined values for Secret key and Current timestamp.

Step 1: get current timestamp (in seconds)
Step result is:
1586286575

Step 2: encrypt the timestamp with your API secret key using HMAC sha256 encrypt algorithm
Step result is (lowercase hexadecimal):
675ff7bd7674f940aec62dadad81fbf79d1f92876d79145ad25af2bf64faee41

Step 3: concatenate timestamp and encrypted timestamp separated by a . (dot)
Step result is:
1586286575.675ff7bd7674f940aec62dadad81fbf79d1f92876d79145ad25af2bf64faee41

Step 4: translate the concatenated string into base64
Step result is (scroll to the right):
MTU4NjI4NjU3NS42NzVmZjdiZDc2NzRmOTQwYWVjNjJkYWRhZDgxZmJmNzlkMWY5Mjg3NmQ3OTE0NWFkMjVhZjJiZjY0ZmFlZTQx

Authentication resources

Timestamp:

HMAC:

base64:

Teams

A team on Sendbee platform is a group of people working for your company using the platform to communicate with customers. Each team consists of members. You can have more then one team and each team can have a number of team members.

Fetch teams

curl -X GET -G "https://api-v2.sendbee.io/teams/teams" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

teams = api.teams([member_id='...'])

for team in teams:
    team.id
    team.name

    for member in team.members:
        member.id
        member.name
        member.role
        member.online
        member.available


Teams fetch response:

{
   "data":[
      {
         "id": "...",
         "name": "...",
         "members": [
            {
               "id": "...",
               "name": "...",
               "online": true|false,
               "available": true|false,
               "role": "owner|admin|team_leader|member"
            },
            ...
         ]
      },
      ...
   ],
   "meta": {
      "current_page": ...,
      "from": ...,
      "to": ...,
      "total": ...,
      "per_page": ...,
      "last_page": ...
   },
   "links": {
      "first": "...",
      "last": "...",
      "next": "...",
      "prev": "...",
   }
}

Fetch teams within your account on Sendbee platform.
With this endpoint you can fetch a list of your teams, and every team in the list contains a list of members.
If you send member_id parameter, you will get all teams where that person is a member.

HTTP Request

GET https://api-v2.sendbee.io/teams/teams

Query Parameters

Parameter Default Required Description
member_id Provide a member ID in order to get only teams where that person is a member

Fetch team members

curl -X PUT -G "https://api-v2.sendbee.io/teams/members" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

members = api.team_members([team_id='...'])

for member in members:
    member.id
    member.name
    member.role
    member.online
    member.available

    for team in member.teams:
        team.id
        team.name


Chatbot status settings response:

{
   "data":[
      {
         "id": "...",
         "name": "...",
         "online": true|false,
         "available": true|false,
         "role": "owner|admin|team_leader|member",
         "teams":[
            {
               "id": "...",
               "name": "..."
            },
            ...
         ]
      },
      ...
   ],
   "meta": {
      "current_page": ...,
      "from": ...,
      "to": ...,
      "total": ...,
      "per_page": ...,
      "last_page": ...
   },
   "links": {
      "first": "...",
      "last": "...",
      "next": "...",
      "prev": "...",
   }
}

Fetch team members within your account on Sendbee platform.
With this endpoint you can fetch a list of users from your company (team members) using Sendbee platform, and every member in the list contains a list of teams where he or she is a member.
If you send team_id parameter, you will get a list of members for that team.

HTTP Request

PUT https://api-v2.sendbee.io/teams/members

Query Parameters

Parameter Default Required Description
team_id Provide a team ID in order to get team members only for that team

Contacts

A contact is a person/entity with whom you have communicated or that subscribed to receive messages from your business. The Sendbee API gives you the ability to subscribe, fetch or update your contacts.

Subscribe contact

curl -X POST -G "https://api-v2.sendbee.io/contacts/subscribe" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"phone": "...", "name": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contact = api.subscribe_contact(
    phone='+...',
    # this is mandatory the most important information
    # about the subscribing contact

    [tags=['...', ...]], 
    # tag new contact
    # if tag doesn't exist, it will be created

    [name='...'], 

    [notes=[...]], 
    # write notes about your new subscriber

    [contact_fields={'__field_name__': '__field_value__', ...}],
    # fill contact fields with your data (value part)
    # contact fields must be pre-created in Sendbee Dashboard
    # any non-existent field will be ignored 

    [block_notifications=[True|False]],
    # prevent sending browser push notification and email 
    # notification to agents, when new contact subscribes
    # (default is True) 

    [block_automation=[True|False]]
    # prevent sending automated template messages to newly
    # subscribed contact (if any is set in Sendbee Dashboard) 
    # (default is True) 
)

contact.id
contact.status
contact.folder
contact.created_at

contact.name
contact.phone

for tag in contact.tags:
    tag.id
    tag.name

for note in contact.notes:
    note.value

for contact_field in contact.contact_fields:
    contact_field.key
    contact_field.value
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$contactData = [
    // contact phone number, MANDATORY
    'phone' => '+...',

    // feel free to specify other optional contact data here
    // ...
];

try {
    $response = $sendbeeApi->subscribeContact($contactData);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Could not subscribe a contact. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $contact \Sendbee\Api\Models\Contact
     */
    $contact = $response->getData();

    // contact is now subscribed (created)
    // $contact contains the newly created contact data
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}

?>

Subscribe contact response:

{
    "data": {
        "id": "...",
        "name": "...",
        "phone": "...",
        "created_at": "...",
        "tags": ["...", ...],
        "status": "...",
        "folder": "...",
        "contact_fields": [
            {
                "key": "...",
                "value": "..."
            },
            ...
        ],
        "notes": ["...", ...]
    }
}

By subscribing a contact, you create a new contact as well.

But to be in compliance with WhatsApp Opt-In rules, you should subscribe/create only contacts who consent to receive your messages in WhatsApp.

Contact consent could be received in form of the web form on your website, having some kind of “Receive your purchase information on WhatsApp” checkbox.
It means contacts are subscribing to your business WhatsApp communication channel.

Read more about WhatsApp Opt-In rules.

HTTP Request

POST https://api-v2.sendbee.io/contacts/subscribe

Data Parameters

Parameter Default Required Description
phone yes Contact phone number. Number must be passed in the E.164 format: +/country code/area code/phone number, UK number example: +442071838750.
tags Tags for this contact (if passed tag name doesn’t match any existing tag name, it will be created as a new one).
name Contact name.
notes Custom notes about the contact.
contact_fields Contact fields defined in your contact fields list. A contact field must be pre-created via the Sendbee Dashboard or Sendbee API. Any non-existent field will be ignored. Send it in the following format: {“[field_name]”: “[field_value]”, …}.
block_notifications True Prevent sending browser push notification and email notification to agents when new contact subscribes.
block_automation True Prevent sending automated template messages to newly subscribed contact (applicable only if an automation rule was created in the Sendbee Dashboard).

Fetch contacts

curl -X GET -G "https://api-v2.sendbee.io/contacts" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contacts = api.contacts(
    [tags=['...', ...]], [status='subscribed|unsubscribed'], 
    [search_query='...'], [page=...]
)

for contact in contacts:
    contact.id
    contact.status
    contact.folder
    contact.created_at

    contact.name
    contact.phone

    for tag in contact.tags:
        tag.id
        tag.name

    for note in contact.notes:
        note.value

    for contact_field in contact.contact_fields:
        contact_field.key
        contact_field.value
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

// optional parameters
$params = [
    'tags' => '', // Filter contacts by tag
    'status' => '', // Filter contacts by status
    'search_query' => '', // Filter contacts by query string
    'page' => 1 // Page number for pagination
];

try {
    $response = $sendbeeApi->getContacts($params);
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    // everything is OK
    $data = $response->getData();
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch contacts response:

{
    "data": [
        {
            "id": "...",
            "name": "...",
            "phone": "...",
            "created_at": "...",
            "tags": ["...", ...],
            "status": "subscribed|unsubscribed",
            "folder": "open|done|spam|notified",
            "contact_fields": [
              {
                  "key": "...",
                  "value": "..."
              },
              ...
            ],
            "notes": ["...", ...]
        },
        ...
    ],
    "meta": {
        "current_page": ...,
        "from": ...,
        "to": ...,
        "total": ...,
        "per_page": ...,
        "last_page": ...
    },
    "links": {
        "first": "...",
        "last": "...",
        "next": "...",
        "prev": "..."
    }
}

HTTP Request

GET https://api-v2.sendbee.io/contacts

Query Parameters

Parameter Default Required Description
phone Contact phone number. Number must be passed in the E.164 format: +/country code/area code/phone number, UK number example: +442071838750.
tags Filter contacts by tags.
status Filter contacts by subscription status. Use subscribed or unsubscribed value.
search_query Filter contacts by string. The query will search through name and phone number fields.
page Page number for pagination.

Update contact

curl -X PUT -G "https://api-v2.sendbee.io/contacts" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"id": "...", ...}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contact = api.update_contact(
    id='...',
    # contact is identified with ID

    [phone='+...'],
    # this is the most important information 
    # about the subscribing contact

    [tags=['...', ...]], 
    # tag new contact
    # if tag doesn't exist, it will be created

    [name='...'],

    [notes=[...]], 
    # write notes about your new subscriber
    # if there are notes already saved for this contact
    # new notes will be appended

    [contact_fields={'__field_name__': '__field_value__', ...}],
    # fill contact fields with your data (value part)
    # contact fields must be pre-created in Sendbee Dashboard
    # any non-existent field will be ignored 
    # if there are fields already filled with data for this contact
    # it will be overwritten with new data 
)

contact.id
contact.status
contact.folder
contact.created_at

contact.name
contact.phone

for tag in contact.tags:
    tag.id
    tag.name

for note in contact.notes:
    note.value

for contact_field in contact.contact_fields:
    contact_field.key
    contact_field.value
<?php
$contactData = [
    // contact id, MANDATORY
    'id' => '...',

    // feel free to specify other optional contact data here
    // ...
];

try {
    $response = $sendbeeApi->updateContact($contactData);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Could not update a contact. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $contact \Sendbee\Api\Models\Contact
     */
    $contact = $response->getData();

    // contact is now updated
    // $contact contains the updated contact data

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Update contacts response:

{
    "data": {
        "id": "...",
        "name": "...",
        "phone": "...",
        "created_at": "...",
        "tags": ["...", ...],
        "status": "subscribed|unsubscribed",
        "folder": "open|done|spam|notified",
        "contact_fields": [
            {
                "key": "...",
                "value": "..."
            },
            ...
        ],
        "notes": ["...", ...]
    }
}

HTTP Request

PUT https://api-v2.sendbee.io/contacts

Data Parameters

Parameter Default Required Description
id Yes Contact ID
phone Contact phone number. Number must be passed in the E.164 format: +/country code/area code/phone number, UK number example: +442071838750.
tags Tag new contact, if tag doesn’t exist, it will be created
name Contact name
notes Custom notes about the contact. Take care, notes are not replaced but are instead appended to existing notes when updating a contact.
contact_fields Contact fields defined in your contact fields list. A contact field must be pre-created in the Sendbee Dashboard or via Sendbee API. Any non-existent field will be ignored. Send it in the following format: {“[field_name]”: “[field_value]”, …}.

Contact tags

A contact tag is a label that can be used to classify contacts. The Sendbee API gives you the ability to fetch, create, update or delete your contact tags.

Fetch contact tags

curl -X GET -G "https://api-v2.sendbee.io/contacts/tags" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

tags = api.tags([name='...'], [page=...])

for tag in tags:
    tag.id
    tag.name
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

// optional parameters
$params = [
    'name' => '...', // Name of the tag
    'page' => 1 // Page number for pagination
];

try {
    $response = $sendbeeApi->getTags($params);
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    // everything is OK

    $data = $response->getData();

    foreach ($data as $tag) {
        /**
         * @var $tag \Sendbee\Api\Models\ContactTag
         */
        echo "\n ID: ", $tag->id;
        echo "\n name: ", $tag->name;
    }
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch tags response:

{
   "data": [
       {
           "id": "...",
           "name": "...",
       },
       ...
   ],
   "meta": {
       "current_page": ...,
       "from": ...,
       "to": ...,
       "total": ...,
       "per_page": ...,
       "last_page": ...
   },
   "links": {
       "first": "...",
       "last": "...",
       "next": "...",
       "prev": "..."
   }
}

HTTP Request

GET https://api-v2.sendbee.io/contacts/tags

Query Parameters

Parameter Default Required Description
name Tag name
page Page number for pagination

Create contact tag

curl -X POST -G "https://api-v2.sendbee.io/contacts/tags" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"name": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

tag = api.create_tag(name='...')

tag.id
tag.name
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // tag name, MANDATORY
    'name' => '...'
];

try {
    $response = $sendbeeApi->createTag($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $tag \Sendbee\Api\Models\ContactTag
     */
    $tag = $response->getData();

    // tag is now created
    // $tag contains the newly created tag data
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}

?>

Create contact tag response:

{
    "data": {
        "id": "...",
        "name": "..."
    }
}

HTTP Request

POST https://api-v2.sendbee.io/contacts/tags

Data Parameters

Parameter Default Required Description
name yes Tag name

Update contact tag

curl -X PUT -G "https://api-v2.sendbee.io/contacts/tags" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"id": "...", "name": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

tag = api.update_tag(id='...', name='...')

tag.id
tag.name
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // tag id, MANDATORY
    'id' => '...',
    // tag name, MANDATORY
    'name' => '...'
];

try {
    $response = $sendbeeApi->updateTag($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $tag \Sendbee\Api\Models\ContactTag
     */
    $tag = $response->getData();

    // tag is now updated
    // $tag contains the updated tag data
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Update contact tag response:

{
    "data": {
        "id": "...",
        "name": "..."
    }
}

HTTP Request

PUT https://api-v2.sendbee.io/contacts/tags

Data Parameters

Parameter Default Required Description
id yes Tag ID
name yes Tag name

Delete contact tag

curl -X DELETE -G "https://api-v2.sendbee.io/contacts/tags" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"id": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

response = api.delete_tag(id='...')

response.message
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // tag id, MANDATORY
    'id' => '...'
];

try {
    $response = $sendbeeApi->deleteTag($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $message \Sendbee\Api\Models\ServerMessage
     */
    $message = $response->getData();
    // record is now deleted
    // $message contains server info message
    print_r($message);

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Delete contact tag response:

{
    "data": {
        "message": "Tag deleted"
    }
}

HTTP Request

DELETE https://api-v2.sendbee.io/contacts/tags

Data Parameters

Parameter Default Required Description
id yes Tag ID

Contact fields

A contact field is a property associated with a contact, that can be populated with specific information such as job title, company details, website, and so on. The Sendbee API gives you the ability to fetch, create, update or delete your contact fields.

Each contact field has a specified data type. Ensure the data you submit when updating a contact field’s value is formatted correctly:

Type Example Value
String Zagreb, Croatia. String values
Boolean true Boolean true/false values
Number 50 Integers
Datetime 2020-01-15 03:04:05 YYYY-MM-DD HH:MM:SS
List [‘option1’, ‘option2’, …] List of options

Fetch contact fields

curl -X GET -G "https://api-v2.sendbee.io/contacts/fields" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contact_fields = api.contact_fields([search_query='...'])

for contact_field in contact_fields:
    contact_field.name
    contact_field.type

    if contact_field.type == 'list':
        contact_field.options
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$params = [
    'search_query' => '', // Filter by query string
    'page' => 1 // Page number for pagination
];

try {
    $response = $sendbeeApi->getContactFields($params);
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    // everything is OK

    $data = $response->getData();

    foreach ($data as $field) {
        /**
         * @var $tag \Sendbee\Api\Models\ContactField
         */
        echo "\n ID: ", $field->id;
        echo "\n type: ", $field->type;
        echo "\n name: ", $field->name;

        foreach ($field->options as $option) {
            /**
             * @var $option string
             */
            echo "\n field -> option: ", $option;
        }

    }
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch contact fields response:

{
   "data": [
       {
           "id": "...",
           "type": "...",
           "name": "...",
           "options": ["...", ...]
       },
       ...
   ],
   "meta": {
       "current_page": ...,
       "from": ...,
       "to": ...,
       "total": ...,
       "per_page": ...,
       "last_page": ...
   },
   "links": {
       "first": "...",
       "last": "...",
       "next": "...",
       "prev": "..."
   }
}

HTTP Request

GET https://api-v2.sendbee.io/contacts/fields

Query Parameters

Parameter Default Required Description
search_query Filter contact fields by string. The query will search for name.
page Page number for pagination.

Create contact field

curl -X POST -G "https://api-v2.sendbee.io/contacts/fields" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"name": "...", "type": "text|number|list|date|boolean"}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contact_field = api.create_contact_field(
    name='...', type='text|number|list|date|boolean'
)

contact_field.id
contact_field.name
contact_field.type

if contact_field.type == 'list':
    contact_field.options
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // name, MANDATORY
    'name' => 'field name',
    // type, one of ['text', 'number', 'list', 'date', 'boolean'], MANDATORY
    'type' => 'text',
    // List of options. Send it only if the field type is a list.
    // values are strings
    'options' => []
];

try {
    $response = $sendbeeApi->createContactField($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $contactField \Sendbee\Api\Models\ContactField
     */
    $contactField = $response->getData();
    // contact field is now created
    // $contactField contains the newly created contact field data
    print_r($contactField);
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Create contact field response:

{
    "data": {
        "id": "...",
        "type": "...",
        "name": "...",
        "options": ["...", ...]
    }
}

When you subscribe or update a contact, use contact field name to link a field value to a contact.

If a contact field type is a list, then you need to send the options parameter.
Options parameter is a list of option names: ['option1', 'option2', ...]

HTTP Request

POST https://api-v2.sendbee.io/contacts/fields

Data Parameters

Parameter Default Required Description
name yes Field name.
type yes Field type. Can be string, number, list, date or boolean.
options List of options. Send it only if the field type is a list.

Update contact field

When you subscribe or update a contact, use contact field name to link a field value to a contact.

If a contact field type is a list, then you need to send the options parameter.
Options parameter is a list of option names: ['option1', 'option2', ...]

curl -X PUT -G "https://api-v2.sendbee.io/contacts/fields" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"id": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

contact_field = api.update_contact_field(
    id='...', [name='...'], [type='text|number|list|date|boolean']
)

contact_field.id
contact_field.name
contact_field.type

if contact_field.type == 'list':
    contact_field.options
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // id, MANDATORY
    'id' => '...',
    // name, MANDATORY
    'name' => 'field name update',
    // type, one of ['text', 'number', 'list', 'date', 'boolean'], MANDATORY
    'type' => 'text',
    // List of options. Send it only if the field type is a list.
    // values are strings
    'options' => []
];

try {
    $response = $sendbeeApi->updateContactField($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $contactField \Sendbee\Api\Models\ContactField
     */
    $contactField = $response->getData();
    // contact field is now updated
    // $contactField contains the updated contact field data
    print_r($contactField);

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Update contact field response:

{
    "data": {
        "id": "...",
        "type": "...",
        "name": "..."
    }
}

HTTP Request

PUT https://api-v2.sendbee.io/contacts/fields

Data Parameters

Parameter Default Required Description
id yes Contact field id.
name Field name.
type Field type. Can be text, number, list, date, boolean.
options List of options. Send it only if the field type is a list.

Delete contact field

curl -X DELETE -G "https://api-v2.sendbee.io/contacts/fields" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"id": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

response = api.delete_contact_field(id='...')

response.message
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // id, MANDATORY
    'id' => '...',
];

try {
    $response = $sendbeeApi->deleteContactField($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $message \Sendbee\Api\Models\ServerMessage
     */
    $message = $response->getData();
    // record is now deleted
    // $message contains server info message
    print_r($message);

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Delete contact field response:

{
    "data": {
        "message": "Contact field deleted"
    }
}

HTTP Request

DELETE https://api-v2.sendbee.io/contacts/fields

Data Parameters

Parameter Default Required Description
id yes Contact field id

Conversations

A conversation is a unique thread of messages that can include Notifications (Message Templates) and Customer Care messages. The Sendbee API gives you the ability to fetch conversations, conversation messages, message templates and send message templates or customer care messages.

Fetch conversations

curl -X GET -G "https://api-v2.sendbee.io/conversations" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

conversations = api.conversations([folder='open|done|spam|notified'], [search_query='...'])

for conversation in conversations:
    conversation.id
    conversation.folder
    conversation.chatbot_active
    conversation.platform
    conversation.created_at

    conversation.contact.id
    conversation.contact.name
    conversation.contact.phone

    conversation.last_message.direction
    conversation.last_message.status
    conversation.last_message.inbound_sent_at
    conversation.last_message.outbound_sent_at
<?php
// optional parameters
$params = [
    // Filter conversations by folder. Specify open, done, spam or notified
    'folder' => '',
    // Any kind of string that will be used to perform filtering
    'search_query' => '',
    // Page number for pagination
    'page' => 1
];

try {
    $response = $sendbeeApi->getConversations($params);
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}


if ($response->isSuccess()) {
    // everything is OK
    $data = $response->getData();

    foreach ($data as $conversation) {
        /**
         * @var $conversation \Sendbee\Api\Models\Conversation
         */
        echo "\n ID: ", $conversation->id;
        echo "\n folder: ", $conversation->folder;
        echo "\n chatbot_active: ", $conversation->chatbot_active;
        echo "\n platform: ", $conversation->platform;
        echo "\n created_at: ", $conversation->created_at;

        echo "\n contact -> id: ", $conversation->contact->id;
        echo "\n contact -> name: ", $conversation->contact->name;
        echo "\n contact -> phone: ", $conversation->contact->phone;

        echo "\n last_message -> direction: ", $conversation->last_message->direction;
        echo "\n last_message -> status: ", $conversation->last_message->status;
        echo "\n last_message -> inbound_sent_at: ", $conversation->last_message->inbound_sent_at;
        echo "\n last_message -> outbound_sent_at: ", $conversation->last_message->outbound_sent_at;

    }
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch conversations response:

{
    "data": [
        {
            "id": "...",
            "folder": "open|done|spam|notified",
            "last_message": {
                "direction": "inbound|outbound",
                "status": "sent|received|delivered|read|failed",
                "inbound_sent_at": "...",
                "outbound_sent_at": "..."
            },
            "contact":{
                "id": "...",
                "phone": "...",
                "name": "..."
            },
            "chatbot_active": true|false,
            "platform": "whatsapp",
            "created_at": "2020-01-14 21:56:49"
        },
        ...
    ],
    "meta": {
        "current_page": ...,
        "from": ...,
        "to": ...,
        "total": ...,
        "per_page": ...,
        "last_page": ...
    },
    "links": {
        "first": "...",
        "last": "...",
        "next": "...",
        "prev": "..."
    }
}

HTTP Request

GET https://api-v2.sendbee.io/conversations

URI Parameters

Parameter Default Required Description
folder open, done, spam or notified
search_query Filter conversations by string. The query will search through contact name and phone number fields.

Fetch conversation messages

curl -X GET -G "https://api-v2.sendbee.io/conversations/messages" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"conversation_id": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

messages = api.messages(conversation_id='...')

for message in messages:
    message.body
    message.media_type
    message.media_url
    message.status
    message.direction
    message.sent_at
<?php
// parameters
$params = [
    // Conversation UUID, MANDATORY
    'conversation_id' => '...',
    // Page number for pagination
    'page' => 1
];

try {
    $response = $sendbeeApi->getMessages($params);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}


if ($response->isSuccess()) {
    // everything is OK
    $data = $response->getData();

    foreach ($data as $message) {
        /**
         * @var $message \Sendbee\Api\Models\Message
         */
        echo "\n body: ", $message->body;
        echo "\n media_type: ", $message->media_type;
        echo "\n media_url: ", $message->media_url;
        echo "\n status: ", $message->status;
        echo "\n direction: ", $message->direction;
        echo "\n sent_at: ", $message->sent_at;

    }
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch conversation messages response:

{
    "data": [
        {
            "body": "...",
            "media_type": "...",
            "media_url": "...",
            "status": "sent|received|delivered|read|failed",
            "direction": "inbound|outbound|template_message|bot",
            "sent_at": "..."
        },
        ...
    ],
    "meta": {
        "current_page": ...,
        "from": ...,
        "to": ...,
        "total": ...,
        "per_page": ...,
        "last_page": ...
    },
    "links": {
        "first": "...",
        "last": "...",
        "next": "...",
        "prev": "..."
    }
}

HTTP Request

GET https://api-v2.sendbee.io/conversations/messages

URI Parameters

Parameter Default Required Description
conversation_id yes Conversation UUID

Message Type

Type Description
text Text in message
file Document in message (PDF, DOC, DOCX, PPT, PPTX, XLS, XLSX)
image Image in message (JPG/JPEG, PNG)
audio Audio in message (AAC, M4A, AMR, MP3, OGG OPUS)
video Video in message (MP4, 3GPP)

Message Status

Status Description
sent Message is sent but not yet delivered to contact’s device
delivered Message is delivered but not yet read by contact
read Contact read the message
received Contact sent the message and the message has been received to your business number
failed Message failed to be sent

Message Direction

Direction Description
inbound Message is sent by contact
outbound Message is sent by your agent or API and is regular message
template_message Message is sent by your agent or API and is template message
bot Message is sent by your chatbot

Fetch message templates

curl -X GET -G "https://api-v2.sendbee.io/conversations/messages/templates" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json"
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

templates = api.message_templates(
    [status="pending|approved|rejected"], [search_query='...']
)

for template in templates:
    template.id
    template.text
    template.tags
    template.keyword
    template.language
    template.status
    template.rejected_reason
<?php
// optional parameters
$params = [
    'status' => 'pending|approved|rejected', // Fetch approved or unapproved templates
    'search_query' => '', // Filter by query string
    'page' => 1 // Page number for pagination
];

try {
    $response = $sendbeeApi->getMessageTemplates($params);
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    // everything is OK

    $data = $response->getData();

    foreach ($data as $messageTemplate) {
        /**
         * @var $messageTemplate \Sendbee\Api\Models\MessageTemplate
         */
        echo "\n ID: ", $messageTemplate->id;
        echo "\n status: ", $messageTemplate->status;
        echo "\n attachment: ", $messageTemplate->attachment;
        echo "\n keyword: ", $messageTemplate->keyword;
        echo "\n text: ", $messageTemplate->text;
        echo "\n language: ", $messageTemplate->language;
        echo "\n rejected_reason: ", $messageTemplate->rejected_reason;

        foreach ($messageTemplate->tags as $tag) {
            /**
             * @var $tag \Sendbee\Api\Models\MessageTemplateTag
             */
            echo "\n tag -> name: ", $tag->name;
        }
    }
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Fetch message templates response:

{
   "data": [
       {
           "id": "...",
           "text": "...",
           "tags": ["...", ...],
           "keyword": "...",
           "language": "...",
           "attachment": "null|image|video|document",
           "status": "pending|approved|rejected",
           "rejected_reason": "..."
       },
       ...
   ],
   "meta": {
       "current_page": ...,
       "from": ...,
       "to": ...,
       "total": ...,
       "per_page": ...,
       "last_page": ...
   },
   "links": {
       "first": "...",
       "last": "...",
       "next": "...",
       "prev": "..."
   }
}

Message templates must be sent to Facebook for approval.
Therefor every message template has status field which can have 3 different values:

Status Description
pending Template is sent for approval and is waiting to be approved or rejected
approved Template is approved and is ready to be used
rejected Template is rejected and cannot be used

If the template is rejected, rejected reason should come in rejected_reason field.
There are a number of reasons why a template can be rejected:

Reason key Description
FORMATTING Formatting is incorrect
COMMERCE_VIOLATION The message template(s) contain content that violates WhatsApp’s Commerce Policy
BUSINESS_VIOLATION The message template(s) contain content that violates WhatsApp’s Business Policy
PROMOTIONAL The message template(s) are considered promotional
ABUSIVE The message template(s) contain potentially abusive or threatening content

Message template can also have attachment.
That means you can send image, video or document URL together with text.
Learn more how to send attachment in Send Template Message section.

HTTP Request

GET https://api-v2.sendbee.io/conversations/messages/templates

URI Parameters

Parameter Default Required Description
status Filter templates by status: pending or approved or rejected
search_query Filter conversations by string. The query will search through contact name and phone number fields.

Send template message

curl -X POST -G "https://api-v2.sendbee.io/conversations/messages/templates/send" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"phone": "...", "template_keyword": "...", "language": "...", "tags": {...}}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

response = api.send_template_message(
    phone='+...',
    template_keyword='...',
    language='...', 
    tags={'__tag_key__': '__tag_value__', ...},
    [attachment='...'],
    [agent_id='...']
)

response.status
response.conversation_id
# save this id, and when you get sent message status requests on
# your webhook, you'll get this same id to identify the conversation
<?php
$data = [
    // phone number to send the message to, MANDATORY
    'phone' => '+...',

    // keyword of an existing template message you are using, MANDATORY
    'template_keyword' => '...',

    // language code of an existing template message you are using, MANDATORY
    'language' => 'en',

    // tags, key-value pairs of data that is injected in placeholders, MANDATORY
    // example:
    //   template message is 'Your order {{order}} has been dispatched. Please expect delivery by {{date}}'
    //   tags are ['order' => 55, 'date' => '2020-12-12']
    //   final message will be 'Your order 55 has been dispatched. Please expect delivery by 2020-12-12'
    'tags' => [],

    // Set to true to disable turning-off chatbot
    'prevent_bot_off' => true,

    // send attachment url for media template mesages
    'attachment' => 'http...'
];

try {
    $response = $sendbeeApi->sendMessageTemplate($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $messageInfo \Sendbee\Api\Models\SentMessage
     */
    $messageInfo = $response->getData();
    // $messageInfo contains message information
    print_r($messageInfo);
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Send template message response:

{
    "data": {
        "status":  "sent|queued",
        "conversation_id": "..."
        // save this id, and when you get sent message status requests on
        // your webhook, you'll get this same id to identify the conversation
    }
}

When a template message is sent using API to a contact for the first time, it will not be visible in the web UI.
But when a template message is sent using API to an existing conversation, it is viewable in the web UI, but the conversation doesn’t appear at the top.

Message template can also have attachment.
That means you can send image, video or document URL together with text.
When you get a list of message templates, every template in that list has attachment field with it’s value.
Attachment field value defines which type of attachment can be sent with message template:

Value Description
image Message template can be sent with image URL: JPG/JPEG, PNG
video Message template can be sent with video URL: MP4, 3GPP
document Message template can be sent with document URL: PDF, DOC, DOCX, PPT, PPTX, XLS, XLSX
null Message template does not support attachment URL

HTTP Request

POST https://api-v2.sendbee.io/conversations/messages/templates/send

Data Parameters

Parameter Default Required Description
phone yes Contact phone number. Number must be passed in the E.164 format: +/country code/area code/phone number, UK number example: +442071838750.
template_keyword yes Every pre-created and approved message template is identified with a keyword.
language yes Language keyword, example: en (for english).
tags yes Template messages use placeholder values (tags) that can be replaced with your custom data inside the curly braces {…}. Example: template message: “Welcome {name}! How can we help you?”, tags: {“name”: contact.name}
prevent_bot_off If there is an active bot running on your Sendbee account, it will be turned off with every message sent using API. Use this parameter to prevent the bot from turning off. Set this parameter to “true”.
agent_id ID of an agent (team member) to whom the conversation will be assigned. Don’t include this parameter if you don’t want to change assigned agent. If the conversation is unassigned, it will stay unassigned if this parameters isn’t included. Learn more how to get an agent ID.
attachment Message template supports attachment. Value of this field should be URL of uploaded image, video or document. Sendbee API does not support attachment upload or hosting, you should upload it your self and provide an URL here.

Send message

curl -X POST -G "https://api-v2.sendbee.io/conversations/messages/send" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"phone": "...", ...'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

response = api.send_message(
    phone='+...', [text='...'], [media_url='...']
)

response.status
response.conversation_id
# save this id, and when you get sent message status requests on
# your webhook, you'll get this same id to identify the conversation
<?php
$data = [
    // phone number to send the message to, MANDATORY
    'phone' => '+...',
    // message text, MANDATORY
    'text' => '...',
    // Media URL for media message
    'media_url' => '',
    // Set to true to disable turning-off chatbot
    'prevent_bot_off' => true,
];

try {
    $response = $sendbeeApi->sendMessage($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $messageInfo \Sendbee\Api\Models\SentMessage
     */
    $messageInfo = $response->getData();
    // $messageInfo contains message information
    print_r($messageInfo);
} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Send message response:

{
    "data": {
        "status":  "sent|queued",
        "conversation_id": "..."
        // save this id, and when you get sent message status requests on
        // your webhook, you'll get this same id to identify the conversation
    }
}

When a message is sent using API to an existing conversation, it is viewable in the web UI, but the conversation doesn’t appear at the top.

Supported media formats

Category Formats
Audio AAC, M4A, AMR, MP3, OGG OPUS
Video MP4, 3GPP
Image JPG/JPEG, PNG
Document PDF, DOC, DOCX, PPT, PPTX, XLS, XLSX

HTTP Request

POST https://api-v2.sendbee.io/conversations/messages/send

Data Parameters

Parameter Default Required Description
phone yes Contact phone number. Number must be passed in the E.164 format: +/country code/area code/phone number, UK number example: +442071838750.
text Text content of the message or caption if you use media_url.
media_url A publicly accessible url to the media file. The url must serve appropriate Content-Length and Content-Type headers for the file being sent.
prevent_bot_off If there is an active bot running on your Sendbee account, it will be turned off with every message sent using API. Use this parameter to prevent the bot from turning off. Set this parameter to “true”.
agent_id ID of an agent (team member) to whom the conversation will be assigned. Don’t include this parameter if you don’t want to change assigned agent. If the conversation is unassigned, it will stay unassigned if this parameters isn’t included. Learn more how to get an agent ID.

Automation

The Sendbee API gives you the ability to manage the status settings of automated replies (chatbot). More automation features to come in the future.

Automated replies status check

curl -X GET -G "https://api-v2.sendbee.io/automation/chatbot/activity/status" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"conversation_id": "..."}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

api.chatbot_activity_status(conversation_id='...')
<?php
$data = [
    // conversation_id, MANDATORY
    'conversation_id' => '...'
];

try {
    $response = $sendbeeApi->getChatbotActivity($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $status \Sendbee\Api\Models\ChatbotStatus
     */
    $status = $response->getData();

    echo "\n conversation_id: ", $status->text;
    echo "\n chatbot_active: ", $status->chatbot_active ? 'ON' : 'OFF';

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Chatbot status settings response:

{
    "data": {
        "conversation_id": "...",
        "chatbot_status": true|false
    }
}

Automated replies (chatbot) are messages that would be automatically triggered based on the keywords that were received in the inbound message. Automated replies can be created in the Sendbee Dashboard.

Use automated replies status check to check if the bot for the conversation is active or not. Every contact is linked to a conversation. Automated replies would automatically turn OFF if a message was sent to a contact by an agent via the Sendbee Dashboard or via the API unless prevent_bot_off parameter is used.

You can turn the chatbot on or off for a certain conversation.

HTTP Request

GET https://api-v2.sendbee.io/automation/chatbot/activity/status

Query Parameters

Parameter Default Required Description
conversation_id yes Conversation UUID

Automated replies status settings

curl -X PUT -G "https://api-v2.sendbee.io/automation/chatbot/activity" \
    -H "X-Auth-Token: ..." \
    -H "X-Api-Key: ..." \
    -H "Accept: application/json" \
    -H "Content-Type": "application/json" \
    -d '{"conversation_id": "...", "active": true|false}'
from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

response = api.chatbot_activity(conversation_id='...', active=True|False)

response.conversation_id
response.chatbot_active # True/False
<?php
$sendbeeApi = new \Sendbee\Api\Client($public_key, $secret);

$data = [
    // conversation_id, MANDATORY
    'conversation_id' => '...',
    // boolean value, true to enable chatbot, false to disable, MANDATORY
    'active' => true | false
];

try {
    $response = $sendbeeApi->chatbotActivity($data);
} catch (\Sendbee\Api\Support\DataException $ex) {
    // handle missing data
    // this happens when required data was not provided
    echo "Missing required data. ", $ex->getMessage();
} catch (\Exception $ex) {
    // handle exception thrown by GuzzleHttp
    // this is most likely due to a network issue
    echo "Could not contact backend endpoint. ", $ex->getMessage();
}

if ($response->isSuccess()) {
    /**
     * @var $tag \Sendbee\Api\Models\ServerMessage
     */
    $message = $response->getData();
    // chatbot activity is now set
    // $message contains server info message
    print_r($message);

} else {
    /**
     * @var $error \Sendbee\Api\Transport\ResponseError
     */
    $error = $response->getError();
    if ($error) {
        // handle error
        echo "\n error type: ", $error->type;
        echo "\n error details: ", $error->detail;
    }
}
?>

Chatbot status settings response:

{
    "data": {
        "message": "Chatbot turned on/off"
    }
}

Automated replies (chatbot) are messages that would be automatically triggered based on the keywords that were received in the inbound message. Automated replies can be created in the Sendbee Dashboard.

Use automated replies status settings to turn automated replies ON or OFF for a certain conversation. Every contact is linked to a conversation. Automated replies would automatically turn OFF if a message was sent to a contact by an agent via the Sendbee Dashboard or via the API unless prevent_bot_off parameter is used.

You can turn the chatbot on or off for a certain conversation.

HTTP Request

PUT https://api-v2.sendbee.io/automation/chatbot/activity

Data Parameters

Parameter Default Required Description
conversation_id yes Conversation UUID
active yes True of False

Webhooks

Webhook request headers section:

{
    "X-Auth-Token": "...",
    "Accept": "application/json",
    "Content-Type": "application/json"
}

A webhook allows you to be automatically notified when something happens in Sendbee without having to constantly poll the API. Webhooks can be activated in the Sendbee Dashboard.

Supported webhooks:

Keyword Category Description
contact.created Contacts New contact has been created
contact.subscription_created Contacts New contact has been subscribed
contact.subscription_updated Contacts Contact subscription has been updated
contact.subscription_unsubscribed Contacts Contact unsubscribed from receiving messages
message.received Messages Message has been received from WhatsApp contact
message.sent Messages Message has been sent by agent or API
message.sent_status Messages Message has been updated with a new status (delivered or read)

Every request to a webhook URL consists of body and headers elements.

Webhook authentication


from sendbee_api import SendbeeApi

api = SendbeeApi(
    '__your_api_key_here__', '__your_secret_key_here__'
)

token = '...'  # taken from the request header
if not api.auth.check_auth_token(token):
    # error! authentication failed!
<?php
// Your API secret
$API_SECRET = '...';
// Received token
$token_from_request_header = '...';

// preferred method: using PHP API
$requestIsValid = \Sendbee\Api\Client::verifyToken($API_SECRET, $token_from_request_header);


// manual method (if you don't want to use the PHP API library)
function verifySendbeeToken($apiSecret, $token, $expirationSeconds = 0)
{
    // sanity check - token should be a non-empty string
    if(!is_string($token) || !$token)
    {
        return false;
    }

    // step 1: decode token using base64 encoding
    $decoded = base64_decode($token);

    // step 2: split encoded string by dot (.) to get timestamp (left part)
    // separated from encrypted string (right part)
    $parts = explode('.', $decoded);

    // sanity check - there should be 2 values
    if(count($parts) != 2)
    {
        return false;
    }

    $receivedTimestamp = $parts[0];
    $receivedHash = $parts[1];

    if($expirationSeconds < 1)
    {
        // set how old can the token be to 15 minutes
        // (or whatever period you think is acceptable for you)
        $expirationSeconds = 60 * 15;
    }

    // step 3: check if the timestamp is not older then specified $expirationSeconds
    if($receivedTimestamp < (time() - $expirationSeconds))
    {
        return false;
    }

    // step 4: encrypt timestamp with your API secret using hmac sha256 and get a hash
    $hash = hash_hmac('sha256', $receivedTimestamp, $apiSecret, false);

    // step 5: compare the hash we received with the one we generated in step 2
    // they need to be equal
    return ($hash == $receivedHash);
}

$requestIsValid = verifySendbeeToken($API_SECRET, $token_from_request_header);

?>

It is highly recommended to authorize every request that Sendbee sends to a webhook, just to be sure that the request indeed is coming from Sendbee on behalf of your account.
To authorize a request coming from Sendbee, use X-Auth-Token token in headers of the request.

To check if the token is valid, please follow these steps:
1. decode token using base64 encoding
2. split encoded string by dot (.) to get timestamp (left part) separated from encrypted string (right part)
3. check if the timestamp is not older then 15 minutes (or whatever period you think is acceptable for you)
5. encrypt timestamp from split string (step 2) with your API secret using hmac sha256
6. compare this encrypted timestamp with encrypted part (step 2), they need to be equal

contact.created

Request body for contact.created

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "type": "contact.created",
}

Every time a contact is created Sendbee sends a request to your webhook URL.
Contact can be created in various ways:
- Contact sends you a message
- Contact subscribes for receiving messages via the custom opt-in source
- You subscribe a contact via Sendbee API

contact.subscription_created

Request body for contact.subscription_created

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "subscribed_at": 123456789,
    "subscribed_via": "API",
    "subscription_updated_at": 123456789,
    "type": "contact.subscription_created",
}

Every time a contact subscribes Sendbee sends a request to your webhook URL.
Contact can be subscribed in various ways:
- Contact subscribes for receiving messages via the custom opt-in source
- You subscribe a contact via Sendbee API

contact.subscription_updated

Request body for contact.subscription_updated

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "subscribed_at": 123456789,
    "subscribed_via": "API",
    "subscription_updated_at": 123456789,
    "type": "contact.subscription_updated",
}

Every time a contact re-subscribes Sendbee sends a request to your webhook URL. Contact can be re-subscribed in various ways:
- Existing contact subscribes for receiving messages via the custom opt-in source
- You subscribe an existing contact via Sendbee API

contact.unsubscribed

Request body for contact.unsubscribed

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "type": "contact.unsubscribed",
}

Every time a contact unsubscribes from receiving notifications by sending a STOP keyword to your business, Sendbee will send a request to your webhook URL.

message.received

Request body for message.received (text message)

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "channel": "whatsapp",
    "content": {
        "text": "...",
    },
    "content_type": "text",
    "conversation_id": "...",
    "destination": "...", // your business phone number
    "direction": "inbound",
    "error": null,
    "sent_at": 123456789,
    "source": "...", // contact phone number
    "type": "message.received",
}

Request body for message.received (media message)

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "channel": "whatsapp",
    "content": {
        "media": {
            "caption": '',
            "type": "image|video|document",
            "url": "...",
        },
    },
    "content_type": "media",
    "conversation_id": "...",
    "destination": "...", // your business phone number
    "direction": "inbound",
    "error": null,
    "sent_at": 123456789,
    "source": "...", // contact phone number
    "type": "message.received",
}

Every time a contact sends a message to your business, Sendbee will send a message to your webhook URL.

message.sent

Request body for message.sent (text message)

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "channel": "whatsapp",
    "content": {
        "text": "...",
    },
    "content_type": "text",
    "conversation_id": "...",
    "destination": "...", // contact phone number
    "direction": "inbound",
    "error": null,
    "sent_at": 123456789,
    "source": "...", // your business phone number
    "type": "message.sent",
}

Request body for message.sent (media message)

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789,
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "channel": "whatsapp",
    "content": {
        "media": {
            "caption": '',
            "type": "image|video|document",
            "url": "...",
        },
    },
    "content_type": "media",
    "conversation_id": "...",
    "destination": "...", // contact phone number
    "direction": "inbound",
    "error": null,
    "sent_at": 123456789,
    "source": "...", // your business phone number
    "type": "message.sent",
}

Every time your agent sends a message to contact, or a message has been sent using API, Sendbee will send a message to your webhook URL.

message.sent_status

Request body for message.sent_status

{
    "business": {
        "id": "...",
        "name": "...",
    },
    "contact": {
        "created_at": 123456789
        "id": "...",
        "name": "...",
        "phone": "...",
    },
    "channel": "whatsapp",
    "content": {...},
    "content_type": "...",
    "conversation_id": "...",
    "destination": "...", // contact phone number
    "direction": "outbound",
    "error": null,
    "sent_at": "2020-01-01 12:00:00",
    "source": "...", // your business phone number
    "status": "sent|delivered|read",
    "type": "message.received",
}

Every time your business sends a message to a contact, Sendbee will send a message to your webhook URL indicating the status of the sent message.