Introduction
The purpose of this document is to describe LINK Mobility Messaging API.
The API can be used to send SMS and Viber messages.
The API uses REST technology with POST methods to HTTPS Endpoints.
LINK Mobility provides 3rd parties with api_key, api_secret, service_id and list of allowed senders.
Base URL's
Type | URL |
---|---|
Production | https://api.msghub.cloud/ |
Testing | https://api-test.msghub.cloud/ |
API methods
Method | Description | Example |
---|---|---|
/send | Send message to end-user | https://api.msghub.cloud/send |
/dlr | Check status of previously send message | https://api.msghub.cloud/dlr |
Request Body
SMS Message
Example JSON (SMS)
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"registered_delivery": true,
"callback_url": "http:\/\/example.com\/index.php",
"context": {
"foo": "bar"
},
"priority": "1024",
"delay": "+11 hours",
"parent_msg_id": "goGkSsMG2bpMtZDBoX8v",
"unique": true,
"max_sms_size": 1
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
msisdn | Valid end-user mobile number | string | Yes |
sc | Sender / Display name | string | Yes |
text | Message to send | string | Yes |
service_id | LINK Mobility Service ID | integer | Yes |
registered_delivery | Request DLR for the message | boolean | No |
priority | Priority of the message | integer/string | No |
delay | Message delay in seconds | integer/string | No |
context | User defined context | array | No |
max_sms_size | Maximum sms’s to send | integer | No |
unique | Do not duplicate message | boolean | No |
SMS length calculation
The maximum length of an SMS depends on the characters set used in its content. Typically, SMS containing only GSM-7 characters are limited to 160 characters while using any Unicode characters will limit the length to 70 symbols. Sending longer messages will be sent and billed as more than one SMS as per the table below:
Number of SMS | Maximum GSM-7 characters | Maximum Unicode characters |
---|---|---|
1 | 160 | 70 |
2 | 306 | 134 |
3 | 459 | 201 |
4 | 612 | 268 |
5 | 765 | 335 |
6 | 918 | 402 |
7 | 1071 | 469 |
8 | 1224 | 536 |
9 | 1377 | 603 |
SMS DLR Statuses
Code | Description |
---|---|
201 | The message is sent to carrier |
202 | The message is delivered to handset |
203 | The message is undelivered (invalid number, queue full, etc.) |
204 | Sending message failed |
205 | The message is rejected from carrier |
206 | Unknown error occurred. Please report this to LINK Mobility. |
Viber specific parameters
Example JSON (Viber)
{
"msisdn": "359XXXXXXXXX",
"sc": "ViberTest",
"text": "Test Viber Message",
"service_id": "1",
"platform": 1,
"registered_delivery": true,
"callback_url": "http:\/\/example.com\/index.php",
"context": {
"foo": "bar"
},
"fallback": {
"sms": "Test Message SMS"
},
"priority": "1024",
"delay": "+11 hours",
"ButtonName": "Cool Button",
"ButtonUrl": "https:\/\/www.linkmobility.bg\/bg",
"ImageUrl": "https:\/\/example.com\/example.jpg",
"parent_msg_id": "goGkSsMG2bpMtZDBoX8v",
"ttl": 120
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
ButtonName | Viber Button Text. Maximum allowed size is 30 characters. | string | No |
ButtonUrl | LINK Mobility Service ID | string | No |
ImageUrl | Viber Image URL | string | No |
fallback | Array of fallback texts | array | No |
platform | Enduser platform. Default: 2 | integer | No |
ttl | Time to live for the message. | integer | No |
Viber File Message specific parameters
Example File Message JSON (Viber)
{
"msisdn": "359XXXXXXXXX",
"sc": "ViberTest",
"service_id": "1",
"platform": 1,
"registered_delivery": true,
"callback_url": "http:\/\/example.com\/index.php",
"fallback": {
"sms": "Test Message SMS"
},
"FileUrl": "https://cdn.storage/files/example.pdf",
"FileName": "Example Filename.pdf",
"parent_msg_id": "goGkSsMG2bpMtZDBoX8v",
"ttl": 120
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
FileUrl | File URL. Maximum size: 200mb. Supported formats: doc, docx, rtf, dot, dotx, odt, odf, fodt, txt, info, pdf, xps, pdax, eps, xls, xlsx, ods, fods, csv, xlsm, xltx | string | Yes |
FileName | Custom filename | string | No |
fallback | Array of fallback texts | array | No |
platform | Enduser platform. Default: 2 | integer | No |
ttl | Time to live for the message. | integer | No |
Viber Video Message specific parameters
Example Video Message JSON (Viber)
{
"msisdn": "359XXXXXXXXX",
"sc": "ViberTest",
"text": "Test Viber Video Message",
"service_id": "1",
"platform": 1,
"registered_delivery": true,
"callback_url": "http:\/\/example.com\/index.php",
"fallback": {
"sms": "Test Message SMS"
},
"ButtonName": "Cool Button",
"ThumbnailUrl": "https:\/\/example.com\/example.jpg",
"VideoUrl": "https://storage.googleapis.com/viber-images/1016444621613da75f04.mp4",
"VideoSize": 10,
"Duration": 30,
"parent_msg_id": "goGkSsMG2bpMtZDBoX8v",
"ttl": 120
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
ButtonName | Viber Button Text. Maximum allowed size is 30 characters. | string | No |
VideoUrl | Video Message URL. Supported formats: 3gp, m4v, mov, mp4 | string | Yes |
ThumbnailUrl | Viber Video Thumbnail URL | string | Yes |
VideoSize | Video Size in MB. Maximum size: 200mb | integer | Yes |
Duration | Video Duration in seconds | integer | Yes |
text | Text for Video Message | string | No* (if button is not present, text is optional) |
fallback | Array of fallback texts | array | No |
platform | Enduser platform. Default: 2 | integer | No |
ttl | Time to live for the message. | integer | No |
There are 3 different use cases for Viber Video Message.
1. Only video in the message.
2. Video + text message.
3. Video + text message + button (the button will redirect to the video url in browser).
Viber Delivery Report
Viber DLR Examples JSON
{
"status": 202,
"status_msg": "seen, done date:2022-07-25 12:55:34",
"sent_timestamp": "2022-07-25 12:55:16",
"dlr_timestamp": "2022-07-25 12:55:35",
"sms_id": "BGP3-62de687e06f8c7.23349902",
"service_id": "5",
"type": "DLR",
"channel": "VIBER"
}
{
"status": 202,
"status_msg": "delivered, done date:2022-07-25 12:55:23",
"sent_timestamp": "2022-07-25 12:55:16",
"dlr_timestamp": "2022-07-25 12:55:23",
"sms_id": "BGP3-62de687e06f8c7.23349902",
"service_id": "5",
"type": "DLR",
"channel": "VIBER"
}
{
"status": 203,
"status_msg": "bad data, done date:2022-07-25 12:58:14",
"sent_timestamp": "2022-07-25 12:58:13",
"dlr_timestamp": "2022-07-25 12:58:14",
"sms_id": "BGP1-62de69304938a8.88127029",
"service_id": "5",
"type": "DLR",
"channel": "VIBER"
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
sms_id | Message ID to check | string | Yes |
service_id | GW3 service | integer | Yes |
status_msg | Message for the DLR event (comma separated) | integer | Yes |
sent_timestamp | When message was sent | datetime | Yes |
dlr_timestamp | When this DLR event was received | datetime | Yes |
type | Event type (DLR/MO) | string | Yes |
channel | The channel of the DLR (in this case viber) | string | Yes |
Push Notification specific parameters
Example Message JSON (Push Notification)
{
"sc": "PushTest",
"service_id": "1",
"fallback": {
"sms": "Test Message SMS"
},
"push": {
"title": "Example title!",
"body": "Example body description!",
"uid": "cloud.msghub.example_df123e3ihuhfdaXXXXX",
"redirect_url": "https://example.com",
"image": "https://cdn.com/examples/image.jpg"
},
"priority": 1024
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
push | Push Notification's payload. Fields: title: string, body: string, uid: string, package: string, redirect_url: string, image: string |
array | Yes* (title & body & uid/package are mandatory parameters, the rest are optional. Note: you can either send to a uid or send to a package which will send to all devices subscribed to this package.) |
msisdn | Msisdn can be used for fallback if sending push 1 by 1 | string | No |
fallback | Array of fallback texts | array | No |
Push Notification Delivery Report Statuses
Value | Description |
---|---|
delivered | The PN is received by the device |
opened | The PN is tapped (seen) by the user |
swiped | The PN is cleared/discarded by the user |
Push Notifications Delivery Report
Push Notifications DLR Examples JSON
{
"status": 202,
"status_msg": "delivered, done date: 2022-08-11 16:31:41",
"sent_timestamp": "2022-08-11 16:31:41",
"dlr_timestamp": "2022-08-11 16:31:43",
"sms_id": "BGP3-62f504b4a24e79.57913864",
"service_id": "1395",
"type": "DLR",
"channel": "PUSH"
}
{
"status": 202,
"status_msg": "swiped, done date: 2022-08-11 16:31:54",
"sent_timestamp": "2022-08-11 16:31:41",
"dlr_timestamp": "2022-08-11 16:31:56",
"sms_id": "BGP3-62f504b4a24e79.57913864",
"service_id": "1395",
"type": "DLR",
"channel": "PUSH"
}
Parameter | Description | Type | Mandatory |
---|---|---|---|
sms_id | Message ID to check | string | Yes |
service_id | GW3 service | integer | Yes |
status_msg | Message for the DLR event (comma separated) | integer | Yes |
sent_timestamp | When message was sent | datetime | Yes |
dlr_timestamp | When this DLR event was received | datetime | Yes |
type | Event type (DLR only for Push) | string | Yes |
channel | The channel of the DLR (in this case Push) | string | Yes |
Response
Example Response
{
"meta": {
"code": 200,
"text": "OK"
},
"data": {
"sms_id": "light-5b83e6df35fe41.14520017",
"request_id": "605aff94c0fde9.89437771"
}
}
Response from the API is JSON encoded string. It contains meta and data field.
The meta field contains status code and text description.
The data field contains additional information about the request, for example the sms_id.
Headers
POST /send HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 75
Content-Type: application/json
Host: api-test.msghub.cloud
x-api-key: $vY$aQLmRIRHI0eZR6vDay5KYm3iTwCYPOkJfjqmjomtnBztDRZqfpV8oirf
x-api-sign: PlBIoNRG5PFdnfb6AoJgT78LlkIYhqPxS4zvjM0Ell3BtCC9Sebtpq2bPYPR3wowtxvPe1Zn6QBT6
Parameter | Value | Type | Mandatory |
---|---|---|---|
Content-type | application/json | string | Yes |
x-api-key | YOUR_API_KEY | string | Yes |
x-api-sign | HASH HMAC signature | string | Yes |
Expect | string | Yes |
Authentication
Creating a signature
<?php
$signature = hash_hmac('sha512', $postData, $api_secret);
private static string HashHmacSha512(string message, string secret)
{
Encoding encoding = Encoding.UTF8;
using (HMACSHA512 hmac = new HMACSHA512(encoding.GetBytes(secret)))
{
var msg = encoding.GetBytes(message);
var hash = hmac.ComputeHash(msg);
return BitConverter.ToString(hash).ToLower().Replace("-", string.Empty);
}
}
import hmac
import hashlib
signature = hmac.new(bytes(API_SECRET, 'utf8'), bytes(data, 'utf8'), hashlib.sha512).hexdigest()
const crypto = require('crypto');
let signature = crypto.createHmac("sha512", secret).update(data).digest('hex');
private static String buildHmacSignature(String value, String secret) {
String result;
try {
Mac hmacSHA512 = Mac.getInstance("HmacSHA512");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(),
"HmacSHA512");
hmacSHA512.init(secretKeySpec);
byte[] digest = hmacSHA512.doFinal(value.getBytes());
BigInteger hash = new BigInteger(1, digest);
result = hash.toString(16);
if ((result.length() % 2) != 0) {
result = "0" + result;
}
} catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException ex) {
throw new RuntimeException("Problem calculating HMAC", ex);
}
return result;
}
require 'openssl'
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), API_SECRET, data)
package main
import (
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
)
h := hmac.New(sha512.New, []byte(Api_secret))
h.Write(dataJson)
signature := hex.EncodeToString(h.Sum(nil))
To authenticate to the API you have to sign the data you post.
Construct the Request Body in JSON format
Create a hash using the shared api_secret
Include the signature in the request headers as x-api-sign
Using the shared api_secret, LINK Mobility creates signature of the received JSON POST data
If LINK Mobility’s signature matches the one included in the request, the request is serviced
Examples
<?php
/**
* Single Message
*/
$api_endpoint = "https://<LINK_MOBILITY_ENDPOINT>/send";
$api_key = '<YOUR_API_KEY>';
$api_secret = '<YOUR_API_SECRET>';
$data = [
'msisdn' => '35988XXXXXXX',
'sc' => '1909',
'text' => 'Test Message!',
'service_id' => '<YOUR_SERVICE_ID>',
];
$data = json_encode($data);
$signature = hash_hmac('sha512', $data, $api_secret);
$headers = [
"Content-Type: application/json",
"x-api-key: {$api_key}",
"x-api-sign: {$signature}",
"Expect: ",
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_endpoint);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result);
var_dump($result);
/**
* Multiple Messages
*/
$api_endpoint = "https://<LINK_MOBILITY_ENDPOINT>/send";
$api_key = '<YOUR_API_KEY>';
$api_secret = '<YOUR_API_SECRET>';
$data = [
[
'msisdn' => '35988XXXXXXX',
'sc' => '1909',
'text' => 'Test Message!',
'service_id' => '<YOUR_SERVICE_ID>',
],
[
'msisdn' => '35988XXXXXXX',
'sc' => '1909',
'text' => 'Test Message!',
'service_id' => '<YOUR_SERVICE_ID>',
],
[
'msisdn' => '35988XXXXXXX',
'sc' => '1909',
'text' => 'Test Message!',
'service_id' => '<YOUR_SERVICE_ID>',
],
];
$data = json_encode($data);
$signature = hash_hmac('sha512', $data, $api_secret);
$headers = [
"Content-Type: application/json",
"x-api-key: {$api_key}",
"x-api-sign: {$signature}",
"Expect: ",
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_endpoint);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result);
var_dump($result);
using System;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Security.Cryptography;
/**
* Single message
*/
namespace SMS
{
class Program
{
private const string apiEndPoint = "https://<LINK_MOBILITY_ENDPOINT>/send";
private const string apiKey = "<YOUR_API_KEY>";
private const string apiSecret = "<YOUR_API_SECRET>";
private class SMSRequestData
{
public string msisdn { get; set; }
public string sc { get; set; }
public string text { get; set; }
public string service_id { get; set; }
}
static async Task Main(string[] args)
{
SMSRequestData data = new SMSRequestData
{
msisdn = "35988XXXXXXX",
sc = "1909",
text = "Test Message!",
service_id = "<YOUR_SERVICE_ID>",
};
string jsonData = JsonSerializer.Serialize(data);
string signature = HashHmacSha512(jsonData, apiSecret);
var postData = new StringContent(jsonData, Encoding.UTF8, "application/json");
using var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", apiKey);
client.DefaultRequestHeaders.Add("x-api-sign", signature);
client.DefaultRequestHeaders.Add("Expect", string.Empty);
var response = await client.PostAsync(apiEndPoint, postData);
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
private static string HashHmacSha512(string message, string secret)
{
Encoding encoding = Encoding.UTF8;
using (HMACSHA512 hmac = new HMACSHA512(encoding.GetBytes(secret)))
{
var msg = encoding.GetBytes(message);
var hash = hmac.ComputeHash(msg);
return BitConverter.ToString(hash).ToLower().Replace("-", string.Empty);
}
}
}
}
/**
* Multiple messages
*/
namespace SMS
{
class Program
{
private const string apiEndPoint = https://<LINK_MOBILITY_ENDPOINT>/send;
private const string apiKey = "<YOUR_API_KEY>";
private const string apiSecret = "<YOUR_API_SECRET>";
private class SMSRequestData
{
public string msisdn { get; set; }
public string sc { get; set; }
public string text { get; set; }
public string service_id { get; set; }
}
static async Task Main(string[] args)
{
List<SMSRequestData> smsRequests = new List<SMSRequestData>()
{
new SMSRequestData
{
msisdn = "35988XXXXXXX",
sc = "1909",
text = "Test Message!",
service_id = "<YOUR_SERVICE_ID>",
},
new SMSRequestData
{
msisdn = "35988XXXXXXX",
sc = "1909",
text = "Test Message!",
service_id = "<YOUR_SERVICE_ID>",
}
new SMSRequestData
{
msisdn = "35988XXXXXXX",
sc = "1909",
text = "Test Message!",
service_id = "<YOUR_SERVICE_ID>",
}
};
string jsonData = JsonSerializer.Serialize(smsRequests);
string signature = HashHmacSha512(jsonData, apiSecret);
var postData = new StringContent(jsonData, Encoding.UTF8, "application/json");
using var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", apiKey);
client.DefaultRequestHeaders.Add("x-api-sign", signature);
client.DefaultRequestHeaders.Add("Expect", string.Empty);
var response = await client.PostAsync(apiEndPoint, postData);
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
private static string HashHmacSha512(string message, string secret)
{
Encoding encoding = Encoding.UTF8;
using (HMACSHA512 hmac = new HMACSHA512(encoding.GetBytes(secret)))
{
var msg = encoding.GetBytes(message);
var hash = hmac.ComputeHash(msg);
return BitConverter.ToString(hash).ToLower().Replace("-", string.Empty);
}
}
}
}
import hmac
import hashlib
import json
import requests
#
# Single message
#
ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send"
API_KEY = "<YOUR_API_KEY>"
API_SECRET = "<YOUR_API_SECRET>"
data = {
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "1"
};
data = json.dumps(data)
signature = hmac.new(bytes(API_SECRET, 'utf8'), bytes(data, 'utf8'), hashlib.sha512).hexdigest()
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY,
"x-api-sign": signature,
"Expect": ""
};
request = requests.post(ENDPOINT, data=data, headers=headers)
print(request.text)
#
# Multiple messages
#
ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send"
API_KEY = "<YOUR_API_KEY>"
API_SECRET = "<YOUR_API_SECRET>"
data = [
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "1"
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "1"
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "1"
}
]
data = json.dumps(data)
signature = hmac.new(bytes(API_SECRET, 'utf8'), bytes(data, 'utf8'), hashlib.sha512).hexdigest()
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY,
"x-api-sign": signature,
"Expect": ""
};
request = requests.post(ENDPOINT, data=data, headers=headers)
print(request.text)
const crypto = require('crypto');
const request = require('request');
const endpoint = "https://<LINK_MOBILITY_ENDPOINT>/send";
const api_key = "<YOUR_API_KEY>";
const secret = "<YOUR_API_SECRET>";
/**
* Single message
*/
let data = {
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "<YOUR_SERVICE_ID>",
};
data = JSON.stringify(data);
let signature = crypto.createHmac("sha512", secret).update(data).digest('hex');
let headers = {
"Content-Type": "application/json",
"x-api-key": `${api_key}`,
"x-api-sign": `${signature}`,
"Expect": "",
};
const callback = (error, response, body) => {
console.log(body);
};
request.post(endpoint, {
headers: headers,
body: data,
callback
});
/**
* Multiple messages
*/
let data = [
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "<YOUR_SERVICE_ID>",
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "<YOUR_SERVICE_ID>",
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test Message!",
"service_id": "<YOUR_SERVICE_ID>",
}
];
data = JSON.stringify(data);
let signature = crypto.createHmac("sha512", secret).update(data).digest('hex');
let headers = {
"Content-Type": "application/json",
"x-api-key": `${api_key}`,
"x-api-sign": `${signature}`,
"Expect": "",
};
const callback = (error, response, body) => {
console.log(body);
};
request.post(endpoint, {
headers: headers,
body: data,
callback
});
/**
* Single message
*/
public class Main {
private static String buildHmacSignature(String value, String secret) {
String result;
try {
Mac hmacSHA512 = Mac.getInstance("HmacSHA512");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(),"HmacSHA512");
hmacSHA512.init(secretKeySpec);
byte[] digest = hmacSHA512.doFinal(value.getBytes());
BigInteger hash = new BigInteger(1, digest);
result = hash.toString(16);
if ((result.length() % 2) != 0) {
result = "0" + result;
}
} catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException ex) {
throw new RuntimeException("Problem calculating HMAC", ex);
}
return result;
}
public static void main(String[] args) throws IOException, InterruptedException {
final String ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send";
final String API_KEY = "<YOUR_API_KEY>";
final String API_SECRET = "<YOUR_API_SECRET>";
String data = "{" +
"\"msisdn\":\"35988XXXXXXX\"," +
"\"sc\":\"1909\"," +
"\"text\":\"Test message!\"," +
"\"service_id\":\"<YOUR_SERVICE_ID>\"" +
"}";
String signature = buildHmacSignature(data, API_SECRET);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(ENDPOINT))
.POST(HttpRequest.BodyPublishers.ofString(data))
.header("Content-Type", "application/json")
.header("x-api-key", API_KEY)
.header("x-api-sign", signature)
/*.header("Expect", "")*/ // must be run with java -Djdk.httpclient.allowRestrictedHeaders=expect
.build();
HttpResponse<String> response = client.send(request,HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
/**
* Multiplce messages
*/
public class Main {
private static String buildHmacSignature(String value, String secret) {
String result;
try {
Mac hmacSHA512 = Mac.getInstance("HmacSHA512");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(),"HmacSHA512");
hmacSHA512.init(secretKeySpec);
byte[] digest = hmacSHA512.doFinal(value.getBytes());
BigInteger hash = new BigInteger(1, digest);
result = hash.toString(16);
if ((result.length() % 2) != 0) {
result = "0" + result;
}
} catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException ex) {
throw new RuntimeException("Problem calculating HMAC", ex);
}
return result;
}
public static void main(String[] args) throws IOException, InterruptedException {
final String ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send";
final String API_KEY = "<YOUR_API_KEY>";
final String API_SECRET = "<YOUR_API_SECRET>";
JSONArray data = new JSONArray(
"[{\"msisdn\":\"35988XXXXXXX\",\"sc\":\"1909\",\"text\":\"Test message!\",\"service_id\":\"<YOUR_SERVICE_ID>\"},{\"msisdn\":\"35988XXXXXXX\",\"sc\":\"1909\",\"text\":\"Test message!\",\"service_id\":\"<YOUR_SERVICE_ID>\"},{\"msisdn\":\"35988XXXXXXX\",\"sc\":\"1909\",\"text\":\"Test message!\",\"service_id\":\"<YOUR_SERVICE_ID>\"}]"
);
String signature = buildHmacSignature(data, API_SECRET);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(ENDPOINT))
.POST(HttpRequest.BodyPublishers.ofString(data))
.header("Content-Type", "application/json")
.header("x-api-key", API_KEY)
.header("x-api-sign", signature)
/*.header("Expect", "")*/ // must be run with java -Djdk.httpclient.allowRestrictedHeaders=expect
.build();
HttpResponse<String> response = client.send(request,HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
require 'json'
require 'openssl'
require 'net/https'
#
# Single message
#
ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send"
API_KEY = "<YOUR_API_KEY>"
API_SECRET = "<YOUR_API_SECRET>"
data = {
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test message!",
"service_id": "<YOUR_SERVICE_ID>"
};
data = data.to_json
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), API_SECRET, data)
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY,
"x-api-sign": signature,
"Expect": ""
};
uri = URI.parse(ENDPOINT)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri, headers)
request.body = data
http.use_ssl = true
response = http.request(request)
puts response.body
#
# Multiple messages
#
ENDPOINT = "https://<LINK_MOBILITY_ENDPOINT>/send"
API_KEY = "<YOUR_API_KEY>"
API_SECRET = "<YOUR_API_SECRET>"
data = [
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test message!",
"service_id": "<YOUR_SERVICE_ID>"
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test message!",
"service_id": "<YOUR_SERVICE_ID>"
},
{
"msisdn": "35988XXXXXXX",
"sc": "1909",
"text": "Test message!",
"service_id": "<YOUR_SERVICE_ID>"
}
];
data = data.to_json
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), API_SECRET, data)
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY,
"x-api-sign": signature,
"Expect": ""
};
uri = URI.parse(ENDPOINT)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri, headers)
request.body = data
http.use_ssl = true
response = http.request(request)
puts response.body
package main
/**
* Single message
*/
import (
"bytes"
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
const (
Endpoint = "https://<LINK_MOBILITY_ENDPOINT>/send"
Api_key = "<YOUR_API_KEY>"
Api_secret = "<YOUR_API_SECRET>"
)
dataMap := map[string]string{
"msisdn": "35988XXXXXXX",
"sc": "1990",
"text": "Test message!",
"service_id": "<YOUR_SERVICE_ID>",
}
dataJson, _ := json.Marshal(dataMap)
h := hmac.New(sha512.New, []byte(Api_secret))
h.Write(dataJson)
signature := hex.EncodeToString(h.Sum(nil))
client := &http.Client{}
req, _ := http.NewRequest("POST", Endpoint, bytes.NewBuffer(dataJson))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-api-key", Api_key)
req.Header.Add("x-api-sign", signature)
req.Header.Add("Expect", "")
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
/**
* Multiple messages
*/
import (
"bytes"
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
)
type message struct {
MSISDN string `json:"msisdn"`
ShortCode string `json:"sc"`
Text string `json:"text"`
ServiceId string `json:"service_id"`
}
func main() {
dataMap := []message{{
"3598888888888",
"1990",
"test 1",
"12345",
},
{
"3598888811111",
"1900",
"test 2",
"4567",
}}
payload, _ := json.Marshal(dataMap)
h := hmac.New(sha512.New, []byte(Api_secret))
h.Write(payload)
signature := hex.EncodeToString(h.Sum(nil))
client := &http.Client{}
req, _ := http.NewRequest("POST", Endpoint, bytes.NewBuffer(payload))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-api-key", Api_key)
req.Header.Add("x-api-sign", signature)
req.Header.Add("Expect", "")
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Response Codes
Code | Description |
---|---|
200 | OK |
400 | Bad Request |
401 | Unauthorized |
402 | Empty required parameters |
403 | Invalid input parameters |
404 | Invalid or empty msisdn |
405 | Invalid or empty service_id |
406 | Invalid or empty text |
407 | Invalid or empty shortcode |
408 | Throttle limit reached |
410 | Empty or invalid ButtonUrl (Viber only) |
411 | Empty or invalid ImageUrl! (Viber only) |
412 | Invalid callback url |
413 | Invalid context data |
414 | Invalid max_sms_size |
415 | SMS with duplicate ID |
500 | Error processing request |
501 | Send text failed |
Using Postman
Signature generation in Postman (Pre-request script)
API_KEY = 'YOUR_API_KEY';
SECRET_KEY = 'YOUR_API_SECRET';
function getAuthHeaderxkey(requestBody) {
var hmacDigest = CryptoJS.HmacSHA512(requestBody, SECRET_KEY).toString(CryptoJS.digest);
return hmacDigest;
}
var Header = require('postman-collection').Header
pm.request.headers.add(new Header("x-api-key: " + API_KEY))
pm.request.headers.add(new Header("x-api-sign: " + getAuthHeaderxkey(request['data'])))
You can download Postman collection from this url: download
The collection includes examples for:
- Testing endpoint for /send method
- Testing endpoint /dlr method
- Production endpoint /send method
- Production endpoint /dlr method
Message Priority
Example using custom high priority
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"priority": "101"
}
Example using predefined priority constant
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"priority": "high"
}
Priority can be added to each message.
The priority range is from 0 to 2048.
Priority can also be set with the predefined constants: low, high, normal;
Predefined constant | Value |
---|---|
low | 2048 |
normal | 1024 |
high | 512 |
Message Delay
Example delay with 5 minutes
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"delay": "300"
}
Example using mnemonic
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"delay": "+10 minutes"
}
The message delay defines when the message should be send.
The delay value is in seconds, but you can also use mnemonics.
Example mnemonics:
1 November 2018 10:00:00
+30 minutes
+10 seconds
2019-10-02 09:00:00
Unique Parameter
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"unique": true
}
When unique parameter is set to true the API will check if currently send message has already been sent and reply with error if so.
The API uses parent_msg_id as unique identifier for the message.
If not provided it will create one using combination of msisdn, sc, text.
Message Size
The maximum SMS size depends on message encoding.
The default encoding for SMS messages is GSM 7 bit.
This encoding is limited to 140 bytes or total of 160 characters.
For characters supported by GSM 7 bit please refer to this link.
UCS-2 encoding supports up to 70 16 bit characters.
If the message is over 70 characters it will be sent as concatenated message.
Concatenated Message
Example of limiting maximum messages to send to 1
{
"msisdn": "359XXXXXXXXX",
"sc": "1909",
"text": "Test SMS Message",
"service_id": "1",
"max_sms_size": 1
}
Concatenated message is a long message (more than 160 characters in 7 bit encoding or more than 70 in UCS-2 encoding).
These messages are split and send individually to the Mobile Operator. (additional charges may occur)
Once received on the end user handset they are recombined again into 1 message.
SMS Fallback
Example Fallback
{
"msisdn": "359XXXXXXXXX",
"sc": "ViberTest",
"text": "Test Viber Message",
"service_id": "1",
"fallback": {
"sms": "Test Message SMS"
}
}
Fallback is functionality that will resend failed Viber messages as SMS.