How to send a Viber Campaign with Fallback SMS

By combining Routee' s Viber and SMS API, you are able to send Viber campaigns with Fallback to SMS, if the recipient has not received your Viber message (eg not a Viber User, Opted out etc).

In this example, you will see step by step how to send a Viber campaign to one recipient and, if the message will not be delivered, fallback to SMS.

First, you have to use the Viber API in order to send your Viber campaign:

All your requests should contain headers for authorization and content type:

KEYVALUE
AuthorizationBearer {access_token}
Content-Typeapplication/json

An example request is shown below:

curl --request POST \
  --url https://connect.routee.net/viber/campaign \
  --header 'authorization: Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4' \
  --header 'content-type: application/json' \
  --data '{
  "campaignName": "Viber-to-SMS",
  "senderInfoTrackingId": "YourRegisteredSenderId",
  "to": ["+3069xxxxxxxx"],
  "body": {
    "text": "This is the viber message!",
    "imageURL": "http://your-image",
    "action": {
    	"targetUrl": "http://button-url",
    	"caption": "Go"
    }
  },
  "ttl": 3600,
  "callbackUrl": "http://www.your-fallback-service"
}'
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/octet-stream");
RequestBody body = RequestBody.create(mediaType, "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}");
Request request = new Request.Builder()
  .url("https://connect.routee.net/viber/campaign")
  .post(body)
  .addHeader("authorization", "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4")
  .addHeader("content-type", "application/json")
  .build();

Response response = client.newCall(request).execute();
var client = new RestClient("https://connect.routee.net/viber/campaign");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4");
request.AddParameter("application/json", "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://connect.routee.net/viber/campaign",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import http.client

conn = http.client.HTTPConnection("connect,routee,net")

payload = "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}"

headers = {
    'authorization': "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    'content-type': "application/json"
    }

conn.request("POST", "viber,campaign", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://connect.routee.net/viber/campaign")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Post.new(url)
request["authorization"] = 'Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4'
request["content-type"] = 'application/json'
request.body = "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}"

response = http.request(request)
puts response.read_body
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://connect.routee.net/viber/campaign",
  "method": "POST",
  "headers": {
    "authorization": "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    "content-type": "application/json"
  },
  "data": "{\n    \"campaignName\": \"Viber-to-SMS\",\n  \t\"senderInfoTrackingId\": \"YourRegisteredSenderId\",\n    \"to\": [\"+3069xxxxxxxx\"],\n \t\t\"body\": {\n   \t\t\"text\": \"This is the viber message!\",\n      \"imageURL\": \"http://your-image\",\n   \t\t\"action\": {\n   \t  \t\t\"targetUrl\": \"http://button-url\",\n   \t  \t\t\"caption\": \"Go\"\n   \t\t}\n \t\t},\n \t\t\"ttl\": 3600,\n    \"callbackUrl\": \"http://www.your-fallback-service\"\n}"
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"authorization": @"Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
                           @"content-type": @"application/json" };

NSData *postData = [[NSData alloc] initWithData:[@"{
    "campaignName": "Viber-to-SMS",
  	"senderInfoTrackingId": "YourRegisteredSenderId",
    "to": ["+3069xxxxxxxx"],
 		"body": {
   		"text": "This is the viber message!",
      "imageURL": "http://your-image",
   		"action": {
   	  		"targetUrl": "http://button-url",
   	  		"caption": "Go"
   		}
 		},
 		"ttl": 3600,
    "callbackUrl": "http://www.your-fallback-service"
}" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://connect.routee.net/viber/campaign"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

The "senderInfoTrackingId" is unique and can be retrieved from Routee Platform. The Applications page contains all the information you need.
In the example, the Viber message contains text, image and button. You can replace the URLs with your desired ones. The name of the campaign is "Viber-to-SMS" and there is only one recipient ("+3069xxxxxxxx").
In order to implement the fallback to SMS, you have to define as "callbackUrl" parameter, your service that handles the statuses of Viber messages and, when needed, uses the SMS API to send SMS.

Within the next hour (since ttl is defined to 3600 sec in the above request) your application at "callbackUrl" will receive a callback notification with information about your message's status.

You will receive a POST HTTP request with the following request body:

{
    "trackingId": "b686ccc8-dce4-4e41-a691-9b501efb87a8",
    "campaignTrackingId": "918a265b-8393-43e5-9114-7fed53a8742e",
    "to": "+3069xxxxxxxx",
    "from": "senderId",
    "country": "GR",
    "campaignName": "Viber-to-SMS",
    "status": {
        "name": "UNDELIVERED",
        "reason": {
            "detailedStatus": "Not Viber User",
            "description": "The recipient is not a Viber user."
        },
        "updatedDate": "2018-10-18T07:25:48.441Z"
    },
    "body": {
        "text": "This is the viber message!",
        "imageUrl": "http://your-image",
        "viberAction": {
            "caption": "Go",
            "targetUrl": "http://button-url"
        }
    },
    "applicationName": "default",
    "direction": "Outbound",
    "originatingService": "Viber",
    "ttl": 3600,
    "price": 0,
    "createdAt": "2018-10-18T07:25:45.441Z"
}

In the above example, the viber message is UNDELIVERED (status.name parameter), because the recipient is not a Viber user (status.reason.detailedStatus). In this case, an SMS to the same recipient has to be sent, since the Viber message never arrived.

So, in order to decide if an SMS has to be sent to a recipient, your application has to check the "status.name" parameter in the callback payload. If its value is "DELIVERED", the viber message has been successfully delivered, so, no other action is required. If the status of the message is one of the following: UNDELIVERED, EXPIRED, FAILED, then an SMS has to be sent.
QUEUED and UNSENT statuses are not included, since QUEUED is the initial status, so you will not receive this with a callback, and UNSENT refers to insufficient balance of your account, so possibly the SMS will also be unsent.
You can use the "status.reason.detailedStatus" in order to add more logic to your application. More details about Viber statuses you can find here.

The final step is to send the fallback SMS, when needed.
If the Viber message has not been delivered, you have to set your application to send an SMS to the same recipient.

curl --request POST \
  --url https://connect.routee.net/sms \
  --header 'authorization: Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4'\
  --header 'content-type: application/json' \
  --data '{ 
  "from": "senderId"
  "body": "This is the SMS fallback.",
  "to" : "+3069xxxxxxxx"
  }'
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/octet-stream");
RequestBody body = RequestBody.create(mediaType, "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }");
Request request = new Request.Builder()
  .url("https://connect.routee.net/sms")
  .post(body)
  .addHeader("authorization", "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4")
  .addHeader("content-type", "application/json")
  .build();

Response response = client.newCall(request).execute();
var client = new RestClient("https://connect.routee.net/sms");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4");
request.AddParameter("application/json", "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://connect.routee.net/sms",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import http.client

conn = http.client.HTTPConnection("connect,routee,net")

payload = "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }"

headers = {
    'authorization': "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    'content-type': "application/json"
    }

conn.request("POST", "sms", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://connect.routee.net/sms")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Post.new(url)
request["authorization"] = 'Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4'
request["content-type"] = 'application/json'
request.body = "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }"

response = http.request(request)
puts response.read_body
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://connect.routee.net/sms",
  "method": "POST",
  "headers": {
    "authorization": "Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
    "content-type": "application/json"
  },
  "data": "{ \n  \"from\": \"senderId\"\n  \"body\": \"This is the SMS fallback.\",\n  \"to\" : \"+3069xxxxxxxx\"\n  }"
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"authorization": @"Bearer 12dc9ff4-7df4-4786-8e7a-a46d317687f4",
                           @"content-type": @"application/json" };

NSData *postData = [[NSData alloc] initWithData:[@"{ 
  "from": "senderId"
  "body": "This is the SMS fallback.",
  "to" : "+3069xxxxxxxx"
  }" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://connect.routee.net/sms"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

You set as recipient ("to" parameter in the above request), the same recipient of the Viber message ("to" parameter in the callback payload). You also define the body of the message and the sender id and your SMS will be sent!

If your Viber campaign has more recipients, then for each message, you will receive a callback notification, so you can decide separately for each message if a fallback SMS is needed or not.

In this way, the communication with your audience is ensured.