NAV
PHP Python C# NodeJS Java Ruby Go

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

Send 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",
    "priority": "1024",
    "delay": "+11 hours",
    "context": {
        "foo": "bar"
    },
    "max_sms_size": 1,
    "unique": true,
    "parent_msg_id": "goGkSsMG2bpMtZDBoX8v"
}
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
callback_url User defined url to receive dlr integer No
priority Priority of the message. Default: 1024 integer/string No
delay Message delay in seconds or string 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
parent_msg_id 3rd party message ID string No

Viber text message

Example JSON (Viber text)

{
    "msisdn": "359XXXXXXXXX",
    "sc": "1909",
    "text": "Test SMS Message",
    "service_id": "1",
    "ttl": 120,
    "platform": 1,
    "registered_delivery": true,
    "callback_url": "http:\/\/example.com\/index.php",
    "priority": "1024",
    "delay": "+11 hours",
    "context": {
       "foo": "bar"
    },
    "max_sms_size": 1,
    "unique": true,
    "parent_msg_id": "goGkSsMG2bpMtZDBoX8v"
    "fallback": {
        "sms": "Test Message SMS"
    }
}
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
callback_url User defined url to receive dlr integer No
priority Priority of the message. Default: 1024 integer/string No
delay Message delay in seconds or string 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
parent_msg_id 3rd party message ID string No
fallback Array of fallback texts array No
ttl Time to live for the message in seconds integer No
platform End user platform. Default: 2 integer No

Viber message with button

Example JSON (Viber with button)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "text": "Test Viber Message",
      "service_id": "1",
      "ButtonName": "Cool Button",
      "ButtonUrl": "https:\/\/www.linkmobility.bg\/bg"
  }
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
ButtonName Viber Button Text. Maximum allowed size is 30 characters. string Yes
ButtonUrl The URL to redirect to string Yes

Viber message with image

Example JSON (Viber with image)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "service_id": "1",
      "ImageUrl": "https:\/\/example.com\/example.jpg"
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
ImageUrl Image URL. Expected formats - PNG,JPEG,jpg. Recommended size: 215x185 string Yes

Viber message with text,image & button

Example JSON (Viber with text,image & button)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "text": "Test Viber Message",
      "service_id": "1",
      "ImageUrl": "https:\/\/example.com\/example.jpg",
      "ButtonName": "Cool Button",
      "ButtonUrl": "https:\/\/www.linkmobility.bg\/bg"
  }
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
ButtonName Viber Button Text. Maximum allowed size is 30 characters. string Yes
ButtonUrl The URL to redirect to string Yes
ImageUrl Image URL. Expected formats - PNG,JPEG,jpg. Recommended size: 215x185 string Yes

Viber message with video

Example JSON (Viber with video)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "service_id": "1",
      "ThumbnailUrl": "https:\/\/example.com\/example.jpg",
      "VideoUrl": "https://storage.googleapis.com/viber-images/1016444621613da75f04.mp4",
      "VideoSize": 10,
      "Duration": 30
  }

Example JSON (Viber with text & video)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "service_id": "1",
      "text": "Test Viber Message",
      "ThumbnailUrl": "https:\/\/example.com\/example.jpg",
      "VideoUrl": "https://storage.googleapis.com/viber-images/1016444621613da75f04.mp4",
      "VideoSize": 10,
      "Duration": 30
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
text Message to send 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

Viber message with text, video & button

Example JSON (Viber with text, video & button)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "service_id": "1",
      "text": "Test Viber Message",
      "ButtonName": "Cool Button",
      "ThumbnailUrl": "https:\/\/example.com\/example.jpg",
      "VideoUrl": "https://storage.googleapis.com/viber-images/1016444621613da75f04.mp4",
      "VideoSize": 10,
      "Duration": 30
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
text Message to send string Yes
ButtonName Viber Button Text. Maximum allowed size is 30 characters. string Yes
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

Viber message with file

Example JSON (Viber with file)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "service_id": "1",
      "FileUrl": "https://cdn.storage/files/example.pdf",
      "FileName": "Example Filename.pdf"
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
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

Viber message with survey(list)

Example JSON (Viber with survey)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "text": "Survey title text",
      "service_id": "1",
      "survey": [
          "option1 text",
          "option2 text",
          "option3 text",
          "option4 text",
          "option5 text"
      ]
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
text Text for Survey Title (Up to 85 characters) string Yes
survey Array of survey options (Number of options can be from 2 to 5, Up to 50 characters per option) array Yes

Example JSON (Viber with carousel)

  {
      "msisdn": "359XXXXXXXXX",
      "sc": "ViberTest",
      "text": "Carousel title text",
      "service_id": "1",
      "carousel": [
          { 
              "title": "Carousel item1 title",
              "imageUrl": "https:\/\/example.com\/example.jpg",
              "primaryButton": {
                  "label": "primary button name",
                  "actionUrl": "https:\/\/www.linkmobility.bg\/"
              },
              "secondaryButton": { 
                  "label": "secondary button name",
                  "actionUrl": "https:\/\/www.linkmobility.bg\/bg"
              }
          },
          {
              "title": "Carousel item2 title",
              "imageUrl": "https:\/\/example.com\/example2.jpg",
              "primaryButton": {
                  "label": "primary button name",
                  "actionUrl": "https:\/\/www.linkmobility.bg\/"
              }
          }
      ]
  }
Parameter Description Type Mandatory
msisdn Valid end-user mobile number string Yes
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
text Text for Carousel Title Up to 1000 characters. Recommended length: 200 characters. string Yes
carousel Array of carousel items (Number of items can be from 2 to 5) array Yes
CarouselItem Description Type Mandatory
title Item title text. From 2 to 38 characters. string Yes
imageUrl Item image URL. Expected formats - PNG,JPEG,jpg. Recommended size: 215x185 string Yes
primaryButton Item Primary button object. Contains Mandatory params label (Up to 10 characters) and actionUrl object Yes
secondaryButton Item Secondary button object. Contains Mandatory params label (Up to 12 characters) and actionUrl object No

Push Notification

Example 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
sc Sender / Display name string Yes
service_id LINK Mobility Service ID integer Yes
push Push object containing the push parameters. See below for details object Yes
msisdn Msisdn can be used for fallback if sending push 1 by 1 string No
fallback Array of fallback texts array No
priority Priority of the message. Default: 1024 integer No
Push parameters Description Type Mandatory
title Title text string Yes
body Notification text string Yes
uid the device ID string Yes*
package Package name (send push to all devices subscribed to this package) string Yes*
redirect_url URL to redirect to when the user taps the notification string No
image Image URL string No

DLR Request Body

Example JSON (DLR)

  {
      "service_id": "1",
      "sms_id": "light-5b83e6df35fe41.14520017"
  }
Parameter Description Type Mandatory
service_id LINK Mobility Service ID integer Yes
sms_id Valid LINK Mobility SMS ID (msg_id) string Yes

Response

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.

Response Status 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
417 Wrong parameter value
418 Button name must not exceed 30 characters!
425 Invalid survey option
426 Invalid carousel item
427 Carousel title must be from 2 to 38 characters
500 Error processing request
501 Send text failed

Send Response Body

Example send Response

{
  "meta": {
      "code": 200,
      "text": "OK"
  },
  "data": {
      "msg_id": "light-5b83e6df35fe41.14520017",
      "sms_id": "light-5b83e6df35fe41.14520017",
      "request_id": "605aff94c0fde9.89437771"
  }
}
{
  "meta": {
    "code": 405,
    "text":"Invalid or empty service_id"
  },
  "data": {
    "request_id":"6888e8afc77d35.99513458"
  }
}
meta Description Type Mandatory
code status code integer Yes
text status description string Yes
data Description Type Mandatory
sms_id LINK Mobility SMS ID string No* (only on success)
msg_id LINK Mobility message ID string No* (only on success)
request_id The ID of the request string Yes

DLR Response Body

Example dlr Response

{
  "meta": {
      "code": 200,
      "text": "OK"
  },
  "data": {
      "sms_id": "light-5b83e6df35fe41.14520017",
      "msg_id": "light-5b83e6df35fe41.14520017",
      "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",
      "request_id": "88350b7cf30e6.37506552"
  }
}
{
  "meta": {
    "code": 200,
    "text": "OK"
  },
  "data": {
    "sms_id": "light-5b83e6df35fe41.14520017",
    "msg_id": "light-5b83e6df35fe41.14520017",
    "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:34",
    "request_id": "76320b3cf30e6.42512532"
  }
}
{
  "meta": {
    "code": 200,
    "text": "OK"
  },
  "data": {
    "sms_id": "light-62de69304938a8.88127029",
    "msg_id": "light-62de69304938a8.88127029",
    "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",
    "request_id": "92420b3cf30e6.32512532"
  }
}
meta Description Type Mandatory
code status code integer Yes
text status description string Yes
data Description Type Mandatory
sms_id LINK Mobility message ID string Yes
msg_id LINK Mobility message ID string Yes
status DLR status integer Yes
status_msg Message for the DLR event (comma separated) string Yes
sent_timestamp When message was sent datetime Yes
dlr_timestamp When this DLR event was received datetime Yes
request_id The ID of the dlr check request string Yes

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 Success SubStatuses

Value Description
delivered The viber message is received by the device
seen The viber message is seen by the user

Push Notification Success SubStatuses

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

Delivery report push

Example JSON (pushed DLR)

{
  "status": 202,
  "status_msg": "003: Message is delivered to recipient, submit date: 2022-07-25 12:25:20, done date:2022-07-25 12:25:24",
  "sent_timestamp":"2022-07-25 12:25:20",
  "dlr_timestamp":"2022-07-25 12:25:24",
  "sms_id":"light-5b83e6df35fe41.14523211",
  "service_id":"1",
  "type":"DLR",
  "channel":"SMS"
}
{
  "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:34",
  "sms_id":"light-5b83e6df35fe41.14520017",
  "service_id":"1",
  "type":"DLR",
  "channel":"VIBER"
}

Delivery reports can also be pushed to 3rd party URL using POST.

The URL can be set by LinkMobility

or the client can use the provided callback_url parameter.

parameters Description Type Mandatory
status DLR status integer Yes
status_msg Message for the DLR event (comma separated) string Yes
sent_timestamp When message was sent datetime Yes
dlr_timestamp When this DLR event was received datetime Yes
sms_id LINK Mobility message ID string Yes
service_id LINK Mobility Service ID string Yes
type Event type (DLR) string Yes
channel The channel of the DLR (SMS/VIBER) string Yes

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.

  1. Construct the Request Body in JSON format

  2. Create a hash using the shared api_secret

  3. Include the signature in the request headers as x-api-sign

  4. Using the shared api_secret, LINK Mobility creates signature of the received JSON POST data

  5. 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))
}

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:

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 encoding depends on the characters used in content.

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 (Unicode) supports up to 70 16 bit characters. e.g. Cyrillic, Chinese, etc.

Sending longer messages will be sent as concatenated message 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

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.

Two Way

MO Push

Example JSON (MO push)

{
  "msisdn": "35989XXXXXXX",
  "sc": "1513",
  "text": "Test",
  "service_id": "1",
  "mno_request_dt": "2022-07-25 12:55:16.77755",
  "mcc": "284",
  "mnc": "1",
  "sms_id": "BGP1-5ba0754b307f73.64142531",
  "type": "MO"
}

MO stands for mobile originated. This is the message send from end-user mobile phone.

LINK Mobility provides 3rd parties with api_key, api_secret, service_id and list of allowed shortcodes. 3rd party should provide endpoint where LINK Mobility should push MO messages.

LINK Mobility pushes these messages to 3rd party endpoint in JSON format.

parameters Description Type Mandatory
msisdn End-user MSISDN string Yes
sc Sender / Display name string Yes
text The sent text message string Yes
service_id LINK Mobility Service ID integer Yes
mno_request_dt When MO message was sent datetime No
mcc Mobile Country Code integer No
mnc Mobile Network Code integer No
sms_id LINK Mobility message ID string Yes
type Type of message string Yes

Headers

3rd party can use x-api-sign hash to verify the message integrity.

Parameter Value Type Mandatory
Content-type application/json string Yes
x-api-sign Hash Signature with 3rd party api_secret string Yes

Response

Example JSON (no replay)

{
  "meta": {
    "code": 200,
    "text": "OK"
  },
  "data": {
  }
}

Example JSON (replay)

{
  "meta": {
    "code": 200,
    "text": "OK"
  },
  "data": {
    "text": "Thank you for your message!"
  }
}

3rd party response should also be in JSON format. It must contain meta and data field

3rd party can reply to the MO message synchronous using the data param text. The provided text will be send back to the end-user.

meta Description Type Mandatory
code status code integer Yes
text status description string Yes
data Description Type Mandatory
text Replay text string No

Response Codes

Code Description
200 OK
400 Bad Request
500 Error processing request

MSISDN encryption

Example MSISDN decryption

<?php

$msisdn = base64_decode($encrypted_msisdn);
$iv_length = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($msisdn, 0, $iv_length);
$msisdn = substr($msisdn, $iv_length);
$msisdn = openssl_decrypt($msisdn, 'aes-256-cbc', $api_secret, 0, $iv);







MSISDN can be encrypted using 3rd party api_secret provided by LINK Mobility.

MSISDN encryption is setting up on service provisioning.

Refer to example for decryption.