Introduction
Welcome to the Number™ REST API documentation.
Use our APIs to seamlessly integrate Number™ functionalities into your website or application.
Client libraries
Number™ 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 the WhatsApp channel as a destination when making Sendbee API calls, as it’s the only channel we support. More channels will be coming soon.
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
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 click-to-chat link
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/
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 Number™ APIs, you need to have an active Number™ account. Create your account at www.number.tm.
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 the Number™ app). |
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 making calls to the Number™ API, in some cases, API endpoints could return a list of data consisting of a larger number of elements. To handle this efficiently, we implemented pagination. Paginated responses are typically returned when making a GET request or any other request that returns a list of data in the response. The paginated response includes three main elements: data, meta, and links.
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 but do not prevent the request from being completed successfully. On the other hand, errors are only returned for fatal conditions that prevent the request from being fulfilled.
Errors
Error in response:
{
"error": {
"detail": "...",
"type": "..."
}
}
In case of an error, the response will only contain the error data. Errors typically occur when a parameter is missing, invalid, or when attempting to update a contact using a contact ID that doesn’t exist. Errors typically occur when a parameter is missing, is invalid, or when attempting to update a contact using a contact ID that doesn’t exist. When such errors occur, the response will provide specific details about the error, helping you identify the issue and take appropriate actions to resolve it.
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 . '.' . $hashedData;
// 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 apiSecret = "...";
Int32 timestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
string hashedData = HashHmac(timestamp.ToString(), apiSecret);
return Base64Encode(timestamp.ToString() + "." + hashedData);
}
private static string HashHmac(string data, string key)
{
using (HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(key)))
{
byte[] a2 = hmac.ComputeHash(Encoding.ASCII.GetBytes(data));
return String.Concat(Array.ConvertAll(a2, x => x.ToString("x2")));
}
}
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 Number™ API utilizes the Auth token to authenticate requests. To create an Auth token for each request, you will need the 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
Please check out the official Number™ API client libraries.
If you are using any of these languages, we highly recommend using our client library. It handles authentication for you, so you don’t need to worry about the authentication process and simplifies the integration, allowing you to focus on building your application.
If you’re using a programming language other than the ones for which we provide client libraries, please consider using these examples as a guide on how to create a valid auth token:
Step-by-step tutorial
If you’re encountering difficulties in generating an authentication token successfully, we recommend following this step-by-step tutorial to test your code. For this tutorial, we will be using predefined values for the Secret key and Current timestamp, making the process easier to understand and implement.
Step 1: get current timestamp (in seconds)
The step result is:
1586286575
Step 2: encrypt the timestamp with your API secret key using HMAC sha256 encrypt algorithm
The step result is (lowercase hexadecimal):
675ff7bd7674f940aec62dadad81fbf79d1f92876d79145ad25af2bf64faee41
Step 3: concatenate timestamp and encrypted timestamp separated by a .
(dot)
The step result is:
1586286575.675ff7bd7674f940aec62dadad81fbf79d1f92876d79145ad25af2bf64faee41
Step 4: translate the concatenated string into base64
The step result is:
MTU4NjI4NjU3NS42NzVmZjdiZDc2NzRmOTQwYWVjNjJkYWRhZDgxZmJmNzlkMWY5Mjg3NmQ3OTE0NWFkMjVhZjJiZjY0ZmFlZTQx
Authentication resources
If you are not familiar with some of the terminology or technology mentioned in the steps above, we recommend reading these resources to get a better understanding.
Timestamp:
- Unix timestamp is a system for describing a point in time. It is the number of seconds that have elapsed since the Unix epoch, that is the time 00:00:00 UTC on 1 January 1970, minus leap seconds: https://en.wikipedia.org/wiki/Unix_time
- Timestamp converter: https://www.unixtimestamp.com/
HMAC:
- HMAC is a specific type of message authentication code (MAC) involving a cryptographic hash function and a secret cryptographic key: https://en.wikipedia.org/wiki/HMAC
- HMAC generator: https://www.freeformatter.com/hmac-generator.html
- HMAC-Sha256 using Java: https://sorenpoulsen.com/calculate-hmac-sha256-with-java
- HMAC-Sha256 using Ruby: https://stackoverflow.com/questions/34855049/using-hmac-sha256-in-ruby
- HMAC-Sha256 using Go: https://golangcode.com/generate-sha256-hmac/
- HMAC-Sha256 using C++: https://stackoverflow.com/questions/37737857/generate-hmac-sha256-hash-using-key-in-c
- some more HMAC-Sha256 examples https://github.com/danharper/hmac-examples
base64:
- Base64 is a scheme designed to carry data stored in binary formats across channels that only reliably support text content: https://en.wikipedia.org/wiki/Base64
- base64 decoder/encoder: https://www.base64decode.org/
Rate Limit
A rate limit refers to the maximum number of API calls that a specific business number can make within a specific time period. If this limit is exceeded, API requests will be throttled, resulting in a 429 error response.
It is important to note that regardless of how many API keys you create in your Number™ account, the rate limit will always be associated with and counted within a specific business number.
Error response
Response body:
{
"detail": "Request was throttled. Expected availability in 5 seconds.",
"error": true,
"type": "throttled"
}
If an API call is throttled due to exceeding the rate limit, server will return the following error response:
429 Too Many Requests
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429
Response headers:
Key | Value |
---|---|
Retry-After | 5 |
How to handle throttled request
When using the Number™ API, it’s essential to be prepared to handle possible 429 error responses. If you encounter a 429 error, you should check for the Retry-After
key in the response headers. This key provides information on how long you should wait before making your next API call.
The Number™ API allows a maximum of 60 calls per minute. For instance, if you make 60 API calls within 30 seconds, the next API call will be throttled, and you will receive a 429 error response with the Retry-After
key in the response headers. The value of the Retry-After key will be 30, indicating that you should wait for 30 seconds before making your next API call. This helps ensure that you stay within the rate limit and avoid further throttling.
Error test endpoint
curl -X GET -G "https://api-v2.sendbee.io/rate-limit/error-test" \
-H "X-Auth-Token: ..." \
-H "X-Api-Key: ..." \
-H "Accept: application/json" \
-H "Content-Type": "application/json"
Error test response:
{
"detail": "Request was throttled. Expected available in 5 seconds.",
"error": true,
"type": "throttled"
}
The purpose of this endpoint is to return a 429 error response, and it doesn’t perform any actual functionality. However, it allows you to access all the necessary data for implementing your solution to handle a 429 error response effectively.
The best part about this endpoint is that any requests made to it won’t be counted towards your rate limit. You can freely query it as much as you want without the concern of hitting the rate limit error.
HTTP Request
GET https://api-v2.sendbee.io/rate-limit/error-test
Request test endpoint
curl -X GET -G "https://api-v2.sendbee.io/rate-limit/request-test" \
-H "X-Auth-Token: ..." \
-H "X-Api-Key: ..." \
-H "Accept: application/json" \
-H "Content-Type": "application/json"
Request test response:
{
"detail": "Request was throttled. Expected availability in 5 seconds.",
"error": true,
"type": "throttled"
}
This endpoint doesn’t do anything, it will return 429 error response once you query it in rate higher than 60 call per minute. With this endpoint you can test your 429 error response handle implementation in real life environment.
Requests to this endpoint add to your rate limit counting, meaning you need to be careful and not to use this endpoint once your app is in the production.
The purpose of this endpoint is to return a 429 error response if you query it at a rate higher than 60 calls per minute. With this endpoint, you have the opportunity to test your 429 error response handling implementation in a production environment.
Requests made to this endpoint count towards your rate limit, so it’s essential to be cautious and avoid using this endpoint in the production environment.
HTTP Request
GET https://api-v2.sendbee.io/rate-limit/request-test
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
URI 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
Team members fetch 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
GET https://api-v2.sendbee.io/teams/members
URI 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=...], [limit=...]
)
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",
"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
URI 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 | 1 | Page number for pagination. | |
limit | 10 | Number of items per page. Maximum is 100. |
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 a contact
# if tag doesn't exist, it will be created
# if you want to remove a tag from a contact, put "-" before the tag name
# example: tags=['-tag1'] # this will remove a "tag1" tag from a contact
[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",
"contact_fields": [
{
"key": "...",
"value": "..."
},
...
],
"notes": ["...", ...]
}
}
HTTP Request
PUT https://api-v2.sendbee.io/contacts
Data Parameters
Parameter | Default | Required | Description |
---|---|---|---|
id | Yes | Contact ID | |
tags | Tag a contact, if tag doesn’t exist, it will be created. If you want to remove a tag from the contact, put “-” (without quotations) before the tag name. (add tag example: tags=[“new_customer”] - this will add a “new_customer” tag to the contact) (remove tag example: tags=[“-new_customer”] - this will remove a “new_customer” tag from the contact) | ||
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=...], [limit=...])
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
URI Parameters
Parameter | Default | Required | Description |
---|---|---|---|
name | Tag name | ||
page | 1 | Page number for pagination. | |
limit | 10 | Number of items per page. Maximum is 100. |
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?id=..." \
-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__'
)
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
URI 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='...'], [page=...], [limit=...])
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
URI Parameters
Parameter | Default | Required | Description |
---|---|---|---|
search_query | Filter contact fields by string. The query will search for name. | ||
page | 1 | Page number for pagination. | |
limit | 10 | Number of items per page. Maximum is 100. |
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?id=..." \
-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__'
)
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
URI 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 conversation list
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'], [search_query='...'],
[date_from=__timestamp__], [date_to=__timestamp__],
[limit=...], [page=...]
)
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 or spam
'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",
"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 or spam | ||
search_query | Filter conversations by string. The query will search through contact name and phone number fields. | ||
date_from | Filter conversations to the ones with the last message (inbound or outbound) AFTER this date and time. Should be UNIX timestamp. | ||
date_to | Filter conversations to the ones with the last message (inbound or outbound) BEFORE this date and time. Should be UNIX timestamp. | ||
page | 1 | Page number for pagination. | |
limit | 10 | Number of items per page. Maximum is 100. |
Fetch one conversation
curl -X GET -G "https://api-v2.sendbee.io/conversation" \
-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__'
)
conversation = api.get_conversation(conversation_id='__conversation__id__')
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
// parameters
$params = [
// Conversation UUID, MANDATORY
'conversation_id' => '...'
];
try {
$response = $sendbeeApi->getConversation($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
/**
* @var $conversation \Sendbee\Api\Models\Conversation
*/
$conversation = $response->getData();
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 conversation response:
[
{
"id": "...",
"folder": "open|done|spam",
"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"
}
]
HTTP Request
GET https://api-v2.sendbee.io/conversation
URI Parameters
Parameter | Default | Required | Description |
---|---|---|---|
conversation_id | yes | conversation UUID |
Update conversation
curl -X PUT -G "https://api-v2.sendbee.io/conversation" \
-H "X-Auth-Token: ..." \
-H "X-Api-Key: ..." \
-H "Accept: application/json" \
-H "Content-Type": "application/json" \
-d '{"conversation_id": ..., "folder": ...}'
from sendbee_api import SendbeeApi
api = SendbeeApi(
'__your_api_key_here__', '__your_secret_key_here__'
)
conversations = api.update_conversation(
conversation_id='__conversation__id__'
folder='open|done|spam'
)
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
// parameters
$params = [
// Conversation UUID, MANDATORY
'conversation_id' => '...',
// Assigned "folder" - 'open', 'done' or 'spam'
'folder' => 'open|done|spam'
];
try {
$response = $sendbeeApi->updateConversation($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;
}
}
?>
Update conversation response:
{
"id": "...",
"folder": "open|done|spam",
"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"
}
HTTP Request
GET https://api-v2.sendbee.io/conversation
Data Parameters
Parameter | Default | Required | Description |
---|---|---|---|
conversation_id | yes | conversation UUID | |
folder | open, done or spam |
Fetch conversation messages
curl -X GET -G "https://api-v2.sendbee.io/conversations/messages?conversation_id=..." \
-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__'
)
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 | |
page | 1 | Page number for pagination. |
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 message template |
bot | Message is sent by your chatbot |
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='...'], [agent_id='...'], [live_inbox=True|False]
)
response.status
response.id
response.message_reference_id
<?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|false,
// trigger real-time events after sending
'live_inbox => true|false,
// assigned agent for the conversation
'agent_id' => '...'
];
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",
// save this id, and when you get sent message status requests on
// your webhook, you'll get this same id to identify the conversation
"id": "__conversation_id__",
// save this id, and when you get sent message status requests on
// your webhook, you'll get this same id to identify message
"message_reference_id": "__message_id__"
}
}
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. | ||
live_inbox | true | If you want to display a message sent via API in your inbox in real-time, set this parameter to “true”. If the parameter is set to “false” a message will not be displayed and your existing conversation list will remain unchanged. |
Whatsapp Message Templates
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='...'],
[page=...], [limit=...]
)
for template in templates:
template.id
template.text
template.tags
template.buttons # available for all Sendbee users onboarded after 11th of December 2020
template.button_tags # available for all Sendbee users onboarded after 11th of December 2020
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;
}
foreach ($messageTemplate->buttons as $button) {
/**
* @var $tag \Sendbee\Api\Models\MessageTemplateButton
*/
echo "\n button -> index: ", $tag->index;
echo "\n button -> type: ", $tag->type;
echo "\n button -> title: ", $tag->title;
echo "\n button -> value: ", $tag->value;
}
}
} 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": ["...", ...],
"buttons": [...], # available for all Sendbee users onboarded after 11th of December 2020,
"button_tags": [...], # available for all Sendbee users onboarded after 11th of December 2020
"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 Message Template 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 message templates by string. The query will search through keywords and template texts. | ||
page | 1 | Page number for pagination. | |
limit | 10 | Number of items per page. Maximum is 100. |
Send message template
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__', ...},
[agent_id='...'],
[live_inbox=True|False]
)
response.status
response.id
response.message_reference_id
<?php
$data = [
// phone number to send the message to, MANDATORY
'phone' => '+...',
// keyword of an existing message template you are using, MANDATORY
'template_keyword' => '...',
// language code of an existing message template you are using, MANDATORY
'language' => 'en',
// tags, key-value pairs of data that is injected in placeholders, MANDATORY
// example:
// message template 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...',
// trigger real-time events after sending
'live_inbox => true|false,
// assigned agent for the conversation
'agent_id' => '...'
];
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 message template response:
{
"data": {
"status": "sent|queued",
// save this id, and when you get sent message status requests on
// your webhook, you'll get this same id to identify the conversation
"id": "__conversation_id__",
// save this id, and when you get sent message status requests on
// your webhook, you'll get this same id to identify message
"message_reference_id": "__message_id__"
}
}
When a message template is sent using API to a contact for the first time and
using live_inbox=false
, it will not be visible in the web UI.
But when a message template is sent using API to an existing conversation and
using live_inbox=false
,
it is viewable in the web UI, but the conversation doesn’t appear at the top.
But if you use live_inbox=true
everything is visible in real-time.
Also, you need to be aware when you are sending a WhatsApp message template, you are using someone’s phone number as a destination. If that contact isn’t already in our database, we will save it automatically, but this contact will then be saved with the phone number only and without any other details like name, tags, email, etc.
If you want to update the contact after sending the message, please use this endpoint:
https://developer.sendbee.io/#update-contact
If you want to create the contact before sending the message, please use this endpoint:
https://developer.sendbee.io/#subscribe-contact
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 | Message templates use placeholder values (tags) that can be replaced with your custom data inside the curly braces {{…}}. Example: message template: “Welcome {{1}}! How can we help you?”, tags: {“1”: “John”} | ||
button_tags | Message template can include dynamic URL button which uses placeholder value (tag) that can be replaced with your custom data inside the curly braces {{…}}. | ||
attachment | Media message template supports attachment. Value of this field should be URL of uploaded image, video or document. Number API does not support attachment upload or hosting, you should upload it your self and provide an URL here. | ||
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. | ||
live_inbox | true | If you want to display a message sent via API in your inbox in real-time, set this parameter to “true”. If the parameter is set to “false” a message will not be displayed and your existing conversation list will remain unchanged. |
Send media message template
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": {...}, "attachment": "..."}'
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 message template you are using, MANDATORY
'template_keyword' => '...',
// language code of an existing message template you are using, MANDATORY
'language' => 'en',
// tags, key-value pairs of data that is injected in placeholders, MANDATORY
// example:
// message template 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 message template 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
}
}
Media message template can 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 | Message templates use placeholder values (tags) that can be replaced with your custom data inside the curly braces {{…}}. Example: message template: “Welcome {{1}}! How can we help you?”, tags: {“1”: “John”} | ||
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 interactive message template
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": {...}, "button_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_name__': '__tag_value__', ...},
button_tags={'__tag_name__': '__tag_value__', ...},
[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 message template you are using, MANDATORY
'template_keyword' => '...',
// language code of an existing message template you are using, MANDATORY
'language' => 'en',
// tags, key-value pairs of data that is injected in placeholders, MANDATORY
// example:
// message template 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' => [],
'button_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 message template 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
}
}
Interactive message templates expand the content you can send recipients beyond the standard message template and media messages template types to include interactive buttons.
There are two types of predefined buttons offered:
Value | Description |
---|---|
Call-to-Action | Allows your customer to call a phone number or visit a website. |
Quick Reply | Allows your customer to return a simple text message. |
These buttons can be attached to text message templates or media message templates.
Once your interactive message templates have been created and approved,
you can use them in notification messages as well as customer service/care messages.
This is an example of message template with quick reply buttons:
When your customer clicks on a quick reply button, a response is sent.
A customer may not click a button and either reply to the interactive message or just send you a message.
This is an example of message template with call-to-action buttons:
Call-to-action button can have dynamic URL suffix: https://example.com/{{1}}
{{1}} is a placeholder which can be replaced with the last part of the URL: page/123
Finally the result is: https://example.com/page/123
Call-to-action button dynamic URL suffix works the same way as message template tag.
They are both placeholder which can be replaced with an actual content.
Use button_tags
API parameter to replace dynamic suffix in call-to-action URL button.
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 | Message templates use placeholder values (tags) that can be replaced with your custom data inside the curly braces {{…}}. Example: message template: “Welcome {{1}}! How can we help you?”, tags: {“1”: “John”} | ||
button_tags | If you’re using call to action URL buttons in message templates with dynamic suffix use placeholder values (tags) that can be replaced with your custom data inside the curly braces {{…}}. Example: call to action URL button: “https://example.com/{{1}}”, button_tags: {“1”: “page/123?param=value”} | ||
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?conversation_id=..." \
-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__'
)
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
URI 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) |
whatsapp.message.template.sent_status | WhatsApp template message has been updated with a new status (delivered or read) | |
whatsapp.message.session.sent_status | WhatsApp session message has been updated with a new status (delivered or read) | |
whatsapp.message.template.approval_status | WhatsApp message template approval status has been updated (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": "...",
"message_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.sent_status",
}
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.
whatsapp.message.template.sent_status
Request body for
whatsapp.message.template.sent_status
{
"business": {
"id": "...",
"name": "...",
},
"contact": {
"created_at": 123456789,
"id": "...",
"name": "...",
"phone": "...",
},
"channel": "whatsapp",
"content": {...},
"content_type": "...",
"conversation_id": "...",
"message_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": "whatsapp.message.template.sent_status",
}
Every time your business sends a WhatsApp template message to a contact, Sendbee will send a message to your webhook URL indicating the status of the sent message.
whatsapp.message.session.sent_status
Request body for
whatsapp.message.session.sent_status
{
"business": {
"id": "...",
"name": "...",
},
"contact": {
"created_at": 123456789,
"id": "...",
"name": "...",
"phone": "...",
},
"channel": "whatsapp",
"content": {...},
"content_type": "...",
"conversation_id": "...",
"message_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": "whatsapp.message.session.sent_status",
}
Every time your business sends a WhatsApp session message to a contact, Sendbee will send a message to your webhook URL indicating the status of the sent message.
whatsapp.message.template.approval_status
Request body for
whatsapp.message.template.approval_status
{
"template_id": "...",
"keyword": "...",
"status": "approved|rejected",
"type": "whatsapp.message.template.approval_status",
}
Every time your pending WhatsApp message template changes its approval state into approved or rejected, Sendbee will send a message to your webhook URL indicating the new state of your template.