Bulk SMS
PHP

Introduction

CM's Bulk SMS Gateway enables you to send text messages to mobile phones all around the world in very high volume. To integrate this functionality into your application, you (or your developers) should implement communication with our API.

The Bulk SMS Gateway API covers the interface between your application and the CM Platform by means of the HTTP protocol. Only bulk (free of charge for the end user) text messages are supported.

Authentication

All requests require your product token, which was e-mailed to you after registration, e.g. 00000000-0000-0000-0000-000000000000

Encryption

Communication with the CM servers should be done using the TLS cryptographic protocol. We no longer support SSLv3

Abbreviations and acronyms

Term Description
MT Mobile Terminated – term for a text message that is sent from your application to a handset.
MO Mobile Originated – term for a text message that is sent from a handset to your application.
SMPP Short Message Peer-to-Peer - standard telecom industry protocol for transferring short message data.

Send a message

Our API supports sending text messages via HTTP. You can send a POST request containing an XML or JSON file, or GET a specific URL. The responses and error handling of the XML and JSON gateways are different, see responses & errors for more detail.

POST requires a valid XML document, UTF-8 encoded. Values should be XML encoded and XML element names are in capitals. The GET call requires that all values are URL encoded.

A POST containing JSON should be sent to a different URL. JSON keys are case insensitive.

Sample Requests

HTTP POST XML

Endpoint URL: https://sgw01.cm.nl/gateway.ashx

<?xml version="1.0" encoding="utf-8"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <BODY>Test message</BODY>
  </MSG>
</MESSAGES>

HTTP POST JSON

Endpoint URL: https://gw.cmtelecom.com/v1.0/message

{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "body": {
                    "content": "Test message"
                }
            }
        ]
    }
}

Please note that the MSG and TO objects are arrays, and can contain multiple values resulting in multiple messages.

HTTP GET

We also maintain a gateway interface that can be addressed using a HTTP GET method. This call is limited in its features and only supports the basic parameters (FROM, TO, BODY and REFERENCE), options such as concatenation (multipart), unicode, and hybrid messaging are not supported. We advise to use our HTTP POST call if possible.

https://sgw01.cm.nl/gateway.ashx?producttoken=00000000-0000-0000-0000-000000000000&body=Example+message+text&to=00447911123456&from=SenderName&reference=your_reference
Parameter Description
PRODUCTTOKEN Required. This is the product token that was sent to you by email. Example: 00000000-0000-0000-0000-000000000000'
MSG Required. The msg-tag signals the start of a message and should comprise of at least a from, to and body-tag. One HTTP-call can support up to 1000 msg elements.
FROM Required. This is the sender name. The maximum length is 11 alphanumerical characters or 16 digits. Example: 'CM Telecom'
TO Required. This is the destination mobile number. Restrictions: this value should be in international format. A single mobile number per request. Example: '00447911123456'
BODY Required. This is the message text. Restrictions: the maximum length is 160 characters.
DCS HTTP POST only. You use the DCS (data coding scheme) paramater to indicate the type of message you are sending. If you set DCS to '0' or do not include the parameter, the messages uses standard GSM encoding. If DCS is set to '8' the message will be encoded using Unicode UCS2. View the Unicode paragraph for more information.
REFERENCE Here you can include your message reference. This information will be returned in a status report so you can match the message and it's status. It should be included in the XML when posting. Restrictions: 1 - 32 alphanumeric characters and reference will not work for demo accounts.
MINIMUMNUMBEROFMESSAGEPARTS / MAXIMUMNUMBEROFMESSAGEPARTS Used when sending multipart or concatenated SMS messages and always used together. Indicate the minimum and maximim of message parts that you allow the gateway to send for this message (also see Multipart). Technically the gateway will first check if a message is larger than 160 characters, if so, the message will be cut into multiple 153 characters parts limited by these parameters.
APPKEY Use an APPKEY for Hybrid Messaging purposes. If an APPKEY is added the gateway will deliver according the settings defined in the App Manager.

import java.awt.*;
import java.applet.*;
import java.io.*;
import java.util.*;
import java.net.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult;

class CMDirectSendMessageExample {
    public static final String URL = "https://sgw01.cm.nl/gateway.ashx";

    public static void main(String[] args) {
        try {
            UUID productToken = UUID.fromString("00000000-0000-0000-0000-000000000000");
            String xml = createXml(productToken, "Company", "00447911123456","Example message text");
            String response = doHttpPost(URL, xml);
            System.out.println("Response: " + response);
            System.in.read();
        } catch (IOException e) {
            System.err.println(e); // Display the string.
        }
    }

    private static String createXml(UUID productToken, String sender, String recipient, String message) {
        try {
            ByteArrayOutputStream xml = new ByteArrayOutputStream();
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);

            // Get the DocumentBuilder
            DocumentBuilder docBuilder = factory.newDocumentBuilder();

            // Create blank DOM Document
            DOMImplementation impl = docBuilder.getDOMImplementation();
            Document doc = impl.createDocument(null, "MESSAGES", null);

            // create the root element
            Element root = doc.getDocumentElement();
            Element authenticationElement = doc.createElement("AUTHENTICATION");
            Element productTokenElement = doc.createElement("PRODUCTTOKEN");
            authenticationElement.appendChild(productTokenElement);
            Text productTokenValue = doc.createTextNode("" + productToken);
            productTokenElement.appendChild(productTokenValue);
            root.appendChild(authenticationElement);

            Element msgElement = doc.createElement("MSG");
            root.appendChild(msgElement);

            Element fromElement = doc.createElement("FROM");
            Text fromValue = doc.createTextNode(sender);
            fromElement.appendChild(fromValue);
            msgElement.appendChild(fromElement);

            Element bodyElement = doc.createElement("BODY");
            Text bodyValue = doc.createTextNode(message);
            bodyElement.appendChild(bodyValue);
            msgElement.appendChild(bodyElement);

            Element toElement = doc.createElement("TO");
            Text toValue = doc.createTextNode(recipient);
            toElement.appendChild(toValue);
            msgElement.appendChild(toElement);

            TransformerFactory tranFactory = TransformerFactory.newInstance();
            Transformer aTransformer = tranFactory.newTransformer();
            aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");

            Source src = new DOMSource(doc);
            Result dest = new StreamResult(xml);
            aTransformer.transform(src, dest);

            return xml.toString();

        } catch (TransformerException ex) {
            System.err.println(ex);
            return ex.toString();
        } catch (ParserConfigurationException p) {
            System.err.println(p);
            return p.toString();
        }
    }

    private static String doHttpPost(String urlString, String requestString) {
        try {
            URL url = new URL(urlString);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);

            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
            wr.write(requestString);
            wr.flush();
            // Get the response
            BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            String response = "";
            while ((line = rd.readLine()) != null) {
                response += line;
            }
            wr.close();
            rd.close();

            return response;
        } catch (IOException ex) {
            System.err.println(ex); return ex.toString();
        }
    }
}
/// There is also a Visual Studio NuGet Package available, see
/// https://get.cmtelecom.com/microsoft-dotnet-nuget-pack/

using System;
using System.Net;
using System.Xml.Linq;
using Newtonsoft.Json.Linq;

namespace CM.Direct.Examples
{
    class Program
    {
        static void Main(string[] args)
        {
            ISmsMessageBuilder messageBuilder;
            Guid productToken = new Guid("CD6398D1-BD65-4B40-BD96-7BCC015702B4");

            //Use XML or JSON per your own preference
            messageBuilder = new JsonSmsMessageBuilder();
            var request = messageBuilder.CreateMessage(productToken,
                    "Company",
                    "0031612345678",
                    "Example message text"
                   );

            var response = doHttpPost(messageBuilder.GetTargetUrl(),
                                      messageBuilder.GetContentType(),
                                      request);
            Console.WriteLine($"Response: {response}");
            Console.ReadKey();
        }

        /// <summary>
        /// Sends a string via HTTP POST to a url
        /// </summary>
        /// <param name="url">The target url to send the string to</param>
        /// <param name="requestString">The string to send</param>
        /// <returns>The response of the url or the error text in case of an error</returns>
        private static string doHttpPost(string url, string contentType, string requestString)
        {
            try
            {
                Console.WriteLine($"Sending request to: {url}");
                var webClient = new WebClient();
                webClient.Headers["Content-Type"] = contentType;
                webClient.Encoding = System.Text.Encoding.UTF8;
                return webClient.UploadString(url, requestString);
            }
            catch (WebException wex)
            {
                return string.Format("{0} - {1}", wex.Status, wex.Message);
            }
        }
    }

    /// <summary>
    /// The gateway accepts both the XML amd JSON formats
    /// </summary>
    public interface ISmsMessageBuilder {
        
        /// <summary>
        /// Creates a string according to the technical requirements
        /// of the CM MT gateway for sending a simple SMS text message
        /// </summary>
        /// <param name="productToken">Your product token</param>
        /// <param name="sender">A sendername/shortcode the SMS message</param>
        /// <param name="message">The text to be sent</param>
        /// <param name="recipient">The recipient's MSISDN</param>
        /// <returns>A string according to the technical requirements of the CM MT gateway,
        /// based on the provided parameters</returns>
        string CreateMessage(Guid productToken,
            string sender,
            string recipient,
            string message);

        /// <summary>
        /// The XML and JSON gateways use different URLs
        /// </summary>
        /// <returns>The target URL of either the XML or JSON gateway</returns>
        string GetTargetUrl();
        
        /// <summary>
        /// The JSON gateway requires you to set the content type to "application/json"
        /// </summary>
        /// <returns>The string of the content type to be used in the HTTP header </returns>
        string GetContentType();
    }

    public class XmlSmsMessageBuilder : ISmsMessageBuilder {
        public string CreateMessage(Guid productToken,
                                    string sender,
                                    string recipient,
                                    string message) {
            return
               new XElement("MESSAGES",
                   new XElement("AUTHENTICATION",
                       new XElement("PRODUCTTOKEN", productToken)
               ),
               new XElement("MSG",
                   new XElement("FROM", sender),
                   new XElement("TO", recipient),
                   new XElement("BODY", message)
               )
            ).ToString();
        }

        public string GetContentType()
        { return "application/xml"; }

        public string GetTargetUrl()
        { return "https://sgw01.cm.nl/gateway.ashx"; }
    }

    /// <summary>
    /// For JSON string building we recommend the Newtonsoft JSON NuGet package
    /// Feel free to substitute with your own preference in .net JSON library
    /// </summary>
    public class JsonSmsMessageBuilder : ISmsMessageBuilder
    {
        public string CreateMessage(Guid productToken,
                            string sender,
                            string recipient,
                            string message) {
            return new JObject {
                ["Messages"] = new JObject {
                    ["Authentication"] = new JObject {
                        ["ProductToken"] = productToken
                    },
                    ["Msg"] = new JArray {
                        new JObject { 
                            ["From"] = sender,
                            ["To"] = new JArray {
                                new JObject { ["Number"] = recipient }
                            },
                            ["Body"] = new JObject {
                                ["Content"] = message
                            }    
                        }
                    }
                }
            }.ToString();
        }

        public string GetContentType()
        { return "application/json"; }

        public string GetTargetUrl()
        { return "https://gw.cmtelecom.com/v1.0/message"; }
    }
}
# Send using XML format
curl -i https://sgw01.cm.nl/gateway.ashx
    -X POST
    -H "Content-type: application/xml"
    -d "<MESSAGES>
          <AUTHENTICATION>
            <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
          </AUTHENTICATION>
          <MSG>
            <FROM>Company</FROM>
            <TO>00447911123456</TO>
            <BODY>Test message</BODY>
            <REFERENCE>Your_reference</REFERENCE>
          </MSG>
        </MESSAGES>"

# Send using JSON format
curl -i https://gw.cmtelecom.com/v1.0/message
     -X POST
     -H "Content-Type: application/json"
     -d '{
            "Messages": {
                "Authentication": {
                    "ProductToken": "00000000-0000-0000-0000-000000000000"
                },
                "Msg": [
                    {
                        "Body": {
                            "Content": "Test message"
                        },
                        "From": "Company",
                        "To": [
                            {
                                "Number": "00447911123456"
                            }
                        ],
                        "Reference": "Your_reference"
                    }
                ]
            }
        }'
<?php
  CMSMS::sendMessage('00447911123456', 'Test message');

  class CMSMS
  {
    static public function buildMessageXml($recipient, $message) {
      $xml = new SimpleXMLElement('<MESSAGES/>');

      $authentication = $xml->addChild('AUTHENTICATION');
      $authentication->addChild('PRODUCTTOKEN', '00000000-0000-0000-0000-000000000000');

      $msg = $xml->addChild('MSG');
      $msg->addChild('FROM', 'Company');
      $msg->addChild('TO', $recipient);
      $msg->addChild('BODY', $message);

      return $xml->asXML();
    }

    static public function sendMessage($recipient, $message) {
      $xml = self::buildMessageXml($recipient, $message);

      $ch = curl_init(); // cURL v7.18.1+ and OpenSSL 0.9.8j+ are required
      curl_setopt_array($ch, array(
          CURLOPT_URL            => 'https://sgw01.cm.nl/gateway.ashx',
          CURLOPT_HTTPHEADER     => array('Content-Type: application/xml'),
          CURLOPT_POST           => true,
          CURLOPT_POSTFIELDS     => $xml,
          CURLOPT_RETURNTRANSFER => true
        )
      );

      $response = curl_exec($ch);

      curl_close($ch);

      return $response;
    }
  }
?>

Batch messages

If you want to send multiple messages with one request, please follow the examples below. You can either declare multiple phone numbers to send the same message to each of the given phone numbers, or declare multiple different messages in one request.

The following examples show both methods of batch sending messages in XML and JSON.

<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <TO>00447911123457</TO>
    <BODY>Test message</BODY>
  </MSG>
  <MSG>
    <FROM>OtherSender</FROM>
    <TO>00447911123458</TO>
    <TO>00447911123459</TO>
    <BODY>Other Test message</BODY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                },{
                    "number": "00447911123457"
                }],
                "body": {
                    "content": "Test message"
                }
            },
            {
                "from": "OtherSender",
                "to": [{
                    "number": "00447911123458"
                },{
                    "number": "00447911123459"
                }],
                "body": {
                    "content": "Other Test message"
                }
            }
        ]
    }
}

References

For each batch of messages you send, you can set a reference. To do so, add <reference>your_reference</reference> to any <msg> elements in an XML body, or "reference": "your_reference" to any "msg" objects in a JSON body. The given reference will apply to the messages sent to the numbers in the matching MSG.

The given reference will be used in the status reports for the message, so you can link the status reports to the sent batch. For more information on status reports, see status report webhooks.

The given reference must be between 1 - 32 alphanumeric characters, and will not work using demo accounts.

The following two examples demonstrate how to implement a reference in your XML or JSON.

<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <BODY>Test message</BODY>
    <REFERENCE>your_reference</REFERENCE>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "body": {
                    "content": "Test message"
                },
                "reference": "your_reference"
            }
        ]
    }
}

Unicode

By default our gateway interprets messages as if sent with the standard 7 bit GSM encoding. If you want to send messages using e.g. Arabic, Cyrillic of Greek characters you will need to use the unicode UCS2 encoding. To set your message up for unicode messaging include <DCS>8</DCS> in your <MSG>-element, or if you're using JSON "DCS": 8 in a MSG object. See the examples below.

Please note that there are a few limitations to using unicode encoded messages:

  • Unicode messages can contain up to 70 characters.
  • You will need to POST the XML or JSON file. A HTTP GET request cannot handle the Unicode characters
  • Another note is that not all operators in the world are able to handle Unicode messages, so you will need to test for which operators it works.
<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <DCS>8</DCS>
    <BODY>Κείμενο διαθέσιμο σε όλες τις γλώσσες</BODY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "NUMBER": "00447911123456"
                }],
                "dcs": 8,
                "body": {
                    "content": "Κείμενο διαθέσιμο σε όλες τις γλώσσες"
                }
            }
        ]
    }
}

Auto detect encoding

It possible to let our gateway do the encoding detection for you. In case it detects characters that are not part of the GSM character set, the message will be delivered as Unicode. Any existing DCS value will be ignored. If the message contains more than 70 characters in Unicode format it will be split into a multipart message. You can limit the number of parts by setting the maximum number of message parts (see also the section on Multipart below).

<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <MINIMUMNUMBEROFMESSAGEPARTS>1</MINIMUMNUMBEROFMESSAGEPARTS>
    <MAXIMUMNUMBEROFMESSAGEPARTS>8</MAXIMUMNUMBEROFMESSAGEPARTS>
    <BODY TYPE="AUTO">Κείμενο διαθέσιμο σε όλες τις γλώσσες</BODY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "minimumNumberOfMessageParts": 1,
                "maximumNumberOfMessageParts": 8,
                "body": {
                    "type": "AUTO",
                    "content": "Κείμενο διαθέσιμο σε όλες τις γλώσσες"
                }
            }
        ]
    }
}

Multipart

To send messages longer than 160 characters you need to send them as multipart message (also called concatenated messages). We will cut the message into more smaller messages and the phone will paste them together again. You will need to add a minimum and maximum of message parts using the <MINIMUMNUMBEROFMESSAGEPARTS> and <MAXIMUMNUMBEROFMESSAGEPARTS> paramaters, or their JSON counterpart.

Please note that there are a few limitations to using multipart messages:

  • Each message part can only contain up to 153 characters.
  • The SMS standard theoretically permits up to 255 message parts. In practice you should try to limit your message to 8 message parts
  • Another note is that not all operators in the world are able to handle multipart messages, so you will need to test for which operators it works.
<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <MINIMUMNUMBEROFMESSAGEPARTS>1</MINIMUMNUMBEROFMESSAGEPARTS>
    <MAXIMUMNUMBEROFMESSAGEPARTS>8</MAXIMUMNUMBEROFMESSAGEPARTS>
    <BODY>Using these settings we can send SMS messages that contain more than 160 characters as if it is one message. Please do note that this limits the length of one message to 152 character.</BODY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "minimumNumberOfMessageParts": 1,
                "maximumNumberOfMessageParts": 8,
                "body": {
                    "content": "Using these settings we can send SMS messages that contain more than 160 characters as if it is one message. Please do note that this limits the length of one message to 152 character."
                }
            }
        ]
    }
}

Hybrid Messaging

Hybrid Messaging is an intelligent way to deliver phone number based messages via SMS or Push through the existing CM Messaging gateway.

Prerequisites:

  • Make sure to implement the Hybrid SDK in your app
  • Create the app in the App manager, select the messaging type, upload the Apple certificates and/or Android keys in the App manager.
  • The App manager will give you an App Key and App Secret, the App Key is needed in the request to the gateway.
<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <APPKEY>00000000-0000-0000-0000-000000000000</APPKEY>
    <BODY>This message will be delivered as a push message.</BODY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "appKey": "00000000-0000-0000-0000-000000000000",
                "body": {
                    "content": "This message will be delivered as a push message."
                }
            }
        ]
    }
}

Custom grouping

The custom grouping field is an optional field that can be used to tag messages. These tags will be used by future CM products, like the Transactions API and SMS campaigns. Despite not being immediately visible to you yet, custom groupings can already be assigned.

Applying custom grouping names to messages helps filter your messages. With up to three levels of custom grouping fields that can be set, subsets of messages can be further broken down. The custom grouping name can be up to 100 characters of your choosing.

It’s recommended to limit the number of unique custom groupings to 1000. Please contact support in case you would like to exceed this number.

<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <BODY>This message uses custom groupings</BODY>
    <CUSTOMGROUPING>Campaign ABC</CUSTOMGROUPING>
    <CUSTOMGROUPING2>Department XYZ</CUSTOMGROUPING2>
    <CUSTOMGROUPING3>Source 123</CUSTOMGROUPING3>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "customGrouping": "Campaign ABC",
                "customGrouping2": "Department XYZ",
                "customGrouping3": "Source 123",
                "body": {
                    "content": "This message uses custom groupings"
                }
            }
        ]
    }
}

Allowed channels

The allowed channels field forces a message to only use certain routes. In this field you can define a list of which channels you want your message to use. Not defining any channels will be interpreted als allowing all channels.

The channels available are:

  • SMS
  • Push

The example request below has the allowed channel "Push" and does not contain "SMS". This means the message will be restricted to only taking "Push" routes.

<?xml version="1.0"?>
<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <BODY>This message defines allowed channels</BODY>
    <ALLOWEDCHANNELS>Push</ALLOWEDCHANNELS>  
    <APPKEY>00000000-0000-0000-0000-000000000000</APPKEY>  
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "body": {
                    "content": "This message defines allowed channels"
                },
                "allowedChannels": ["Push"],
                "appKey": "00000000-0000-0000-0000-000000000000"
            }
        ]
    }
}

Validity period

If you wish to specify a time at which a delayed MT can be considered irrelevant, you can supply a date & time in the "validity" field. Our system will consider the MT as failed if it was not successfully delivered before that time.

The default validity time is 4 hours, and the maximum validity period is 48 hours.

<MESSAGES>
  <AUTHENTICATION>
    <PRODUCTTOKEN>00000000-0000-0000-0000-000000000000</PRODUCTTOKEN>
  </AUTHENTICATION>
  <MSG>
    <FROM>SenderName</FROM>
    <TO>00447911123456</TO>
    <BODY>Test message</BODY>
    <VALIDITY>2017-04-21 11:45 GMT</VALIDITY>
  </MSG>
</MESSAGES>
{
    "messages": {
        "authentication": {
            "producttoken": "00000000-0000-0000-0000-000000000000"
        },
        "msg": [ {
                "from": "SenderName",
                "to": [{
                    "number": "00447911123456"
                }],
                "body": {
                    "content": "Test message"
                },
                "validity": "2017-04-20 11:50 GMT"
            }
        ]
    }
}

You can supply the time zone for the validity period using either of the following formats:

  • 2017-04-20 11:50:05 GMT
  • 2017-04-20 11:50:05+8
  • 2017-04-20 11:55:05-07:00

Responses & Errors

The XML gateway and JSON gateway have different output, and respond very differently to errors.

When sending a request with an invalid part to the XML gateway, NO MESSAGES are created and the entire request is rejected. You will receive a plain text response with details why the request was rejected.

When sending a request with an invalid part to the JSON gateway, it will continue to check the other TO objects and MSG objects available and send the correctly formatted values. In the JSON response, you can find details per message. With each message you receive the MSISDN of the failed message (if present), the accepted or rejected status, your reference for the message (if present), the amount of message parts we created for that message, and a description why the message was rejected (if present).

Example response of a failed XML request:

Status: 200 OK

Error: ERROR No account found for the given authentication

Examples of responses of failed JSON requests:

Entire request incorrect: Status: 400 Bad Request

{
  "details": "No account found for the given authentication",
  "errorCode": 101,  //See table "JSON POST Error codes" below
  "messages": []
}

Incorrect MSG and a correct message: Status: 200 OK

{
  "details": "Created 1 message(s)",
  "errorCode": 201, //See table "JSON POST Error codes" below
  "messages": [
    {
      "to": "00447911123456",
      "status": "Accepted",
      "reference": "your_reference_A",
      "parts": 1,
      "messageDetails": null,
      "messageErrorCode": 0 //See table "JSON POST Error codes" below
    },
    {
      "to": "00447911123457",
      "status": "Rejected",
      "reference": "your_reference_B",
      "parts": 0,
      "messageDetails": "A body without content was found",
      "messageErrorCode": 304 //See table "JSON POST Error codes" below
    }
  ]
}

All incorrect: Status: 400 Bad Request

{
  "details": "Created 0 message(s)",
  "errorCode": 201,
  "messages": [
    {
      "to": "0044791112345a",
      "status": "Rejected",
      "reference": "your_reference_A",
      "parts": 0,
      "messageDetails": "Gsm '0044791112345a' is not a number.",
      "messageErrorCode": 303 //See table "JSON POST Error codes" below
    },
    {
      "to": "00447911123456",
      "status": "Rejected",
      "reference": null,
      "parts": 0,
      "messageDetails": "A body without content was found",
      "messageErrorCode": 304 //See table "JSON POST Error codes" below
    }
  ]
}

GET responses

HTTP status Error text Remarks
400 (none) No HTTP GET or POST was used to send your request
200 Error: ERROR Unknown error An unexpected error occurred. Check the provided values. Contact CM for support.
200 (empty) The request was accepted
200 Error: ERROR No account found for the given authentication No account found for the provided product token.
200 Error: ERROR Insufficient balance. You are out of trial messages. Order new messages via your dashboard.
200 Error: ERROR Message is unrouteable. Your request could not be routed. Contact CM for support.
200 Error: ERROR Parameter 'producttoken' contains an invalid value: '' Invalid or missing product token
200 Error: ERROR No sender name provided ‘from’ parameter is missing or its value was empty
200 Error: ERROR Parameter 'to' contains an invalid value: '' The value for the ‘to’ parameter is not a valid MSISDN
200 Error: ERROR Parameter 'body' is required The value for the ‘body’ parameter is missing

XML POST responses

HTTP status Error text Remarks
400 (none) No HTTP GET or POST was used to send your request
200 Error: ERROR Unknown error An unexpected error occurred. Check the provided values. Contact CM for support.
200 (empty) The request was accepted
200 Error: ERROR No account found for the given authentication No account found for the provided product token.
200 Error: ERROR Insufficient balance. You are out of trial messages. Order new messages via your dashboard.
200 Error: ERROR Message is unrouteable. Your request could not be routed. Contact CM for support.
200 Error: ERROR Invalid product token. Invalid or missing product token
200 Error: ERROR No FROM field found in a MSG node. The ‘FROM’ element is missing within the ‘MSG’ element
200 Error: ERROR A MESSAGES node requires at least one MSG node A MSG node within the MESSAGE node is required and is missing.
200 Error: ERROR No phone numbers found. Message will not be sent. The MSISDN value for the TO element is missing
200 Error: ERROR Rejected: Gsm '' is not a number. The value for the TO element is not a valid MSISDN

JSON POST responses

HTTP status Error text Remarks
405 (none) No HTTP GET or POST was used to send your request
500 "details": "Unknown Error" An unexpected error occurred. Check the provided values. Contact CM for support.
400 "details": "No account found for the given authentication" No account found for the provided product token.
400 "details": "Insufficient balance." You are out of trial messages. Order new messages via your dashboard.
400 "details": "Message is unroutable." Your request could not be routed. Contact CM for support.
400 "details": "Invalid product token." Invalid or missing product token
400 "details": "A MESSAGES object requires at least one MSG object" A MSG object within the MESSAGE object is required and is missing.
400 "details": "Invalid JSON" The given JSON is malformed. Please validate your JSON syntax and try again.
200 "details": "Created [x] message(s)" An [x] amount of messages have been accepted. See the messages objects for further details.
- "messageDetails": "No FROM field found in a MSG object." The ‘FROM’ element is missing within the ‘MSG’ element
- "messageDetails": "Empty mobilenumber field, MT ignored" The MSISDN value for the TO element is missing
- "messageDetails": "Rejected: Gsm '[msisdn]' is not a number." The value for the TO element is not a valid MSISDN
- "messageDetails": "[Object] object is an invalid type, must be an array" The stated [Object] should be an array. Even if this contains one element.
- "messageDetails": "No body field was found" The ‘BODY’ element is missing within the ‘MSG’ element
- "messageDetails": "A body without content was found" The ‘BODY’ element is missing ‘CONTENT’

JSON POST Error codes

Error code Description
0 Ok
999 Unknown error, please contact CM support
101 Authentication of the request failed
102 The account using this authentication has insufficient balance
103 The product token is incorrect
201 This request has one or more errors in its messages. Some or all messages have not been sent. See MSGs for details
202 This request is malformed, please confirm the JSON and that the correct data types are used
203 The request's MSG array is incorrect
301 This MSG has an invalid From field (per msg)
302 This MSG has an invalid To field (per msg)
303 This MSG has an invalid MSISDN in the To field (per msg)
304 This MSG has an invalid Body field (per msg)
305 This MSG has an invalid field. Please confirm with the documentation (per msg)
401 Message has been spam filtered
402 Message has been blacklisted
403 Message has been rejected
500 An internal error has occurred

Status report webhook

The SMS platform has the option to communicate with a web server whenever a message had an updated status. This so-called status report webhook can be configured on the settings page. The status reports will be communicated using a HTML GET request.

Configure status reports

You can configure your status report webhook in the 'Messaging Gateway'-app. Please refer to this article in our Help center for more information.

Parameters
Name Format Description
CREATED_S Datetime The moment when the status report was registered in the system (yyyy-mm-ddThh:ii:ss)
DATETIME_S Datetime The moment when the status report was sent to the endpoint of the customer (yyyy-mm-ddThh:ii:ss)
GSM String The telephonenumber of the message recipient
REFERENCE String The message reference provided by the customer
STANDARDERRORTEXT String The description of the error if the message is in an error-state
STATUS Integer The code describing the current state of the message. 0=accepted by the operator, 1=rejected by CM or operator,2=delivered, 3=failed (message was not delivered and will not be delivered)
STATUSDESCRIPTION String The description of the current state of the message
+GSM String The telephonenumber of the recipient with preceding + instead of 00
EXTERNALSTATUSDESCRIPTION String The status description our system received from the supplier
ID Integer The id of the message in the system
OPERATOR String The MCCMNC of the operator for the recipient
RECIPIENT String The telephonenumber of the message recipient
SRCREATED Datetime The moment when the status report was registered in the system (mm/dd/yyyy hh:ii:ss P)
SRCREATED_S Datetime The moment when the status report was registered in the system (yyyy-mm-ddThh:ii:ss)
STATUSCODESTRING String The same value as [STANDARDERRORTEXT], but lowercase
STATUSISSUCCESS Integer The success-state of the status code, 1 on success , 0 on error
TIME Time The time when the status report was sent to the endpoint of the customer (hh:ii:ss P)
CUSTOMGROUPING string The custom grouping set for this MT by the user. See Custom Grouping
CUSTOMGROUPING2 string The second custom grouping set for this MT by the user. See Custom Grouping
CUSTOMGROUPING3 string The third custom grouping set for this MT by the user. See Custom Grouping
Errors
Error code Short description Full description
5 Message not delivered at third party The message has been confirmed as undelivered but no detailed information related to the failure is known.
7 Message not delivered at operator because recipient has insufficient credit Temporary - Used to indicate to the client that the message has not yet been delivered due to insufficient subscriber credit but is being retried within the network.
8 Message expired at third party Temporary - Used when a message expired (could not be delivered within the life time of the message) within the operator SMSC but is not associated with a reason for failure.
20 Message not delivered because of a malformed request Used when a message in its current form is undeliverable.
21 Message expired at operator Temporary - Only occurs where the operator accepts the message before performing the subscriber credit check. If there is insufficient credit then the operator will retry the message until the subscriber tops up or the message expires. If the message expires and the last failure reason is related to credit then this error code will be used.
22 Message not delivered at operator because recipient has insufficient credit Temporary - Only occurs where the operator performs the subscriber credit check before accepting the message and rejects messages if there are insufficient funds available.
23 Message not delivered because of an incorrect recipient number (invalid/blacklisted/barred) Used when the message is undeliverable due to an incorrect / invalid / blacklisted / permanently barred MSISDN for this operator. This MSISDN should not be used again for message submissions to this operator.
24 Message not delivered because the recipient was unreachable Temporary - Used when a message is undeliverable because the subscriber is temporarily absent, e.g. his/her phone is switch off, he/she cannot be located on the network.
25 Message not delivered at third party Temporary - Used when the message has failed due to a temporary condition in the operator network. This could be related to the SS7 layer, SMSC or gateway.
26 Message not delivered because of a temporary handset issue (simcard full/memory exceeded/SME busy) Temporary - Used when a message has failed due to a temporary phone related error, e.g. SIM card full, SME busy, memory exceeded etc. This does not mean the phone is unable to receive this type of message/content (refer to error code 27).
27 Message not delivered because of a permanent handset issue (unable to receive SMS) Permanent - Used when a handset is permanently incompatible or unable to receive this type of message.
28 Message not delivered because submission speed is too high (throttling errors) Used if a message fails or is rejected due to suspicion of SPAM on the operator network. This could indicate in some geographies that the operator has no record of the mandatory MO required for an MT.
29 Message not delivered because content is not permitted Permanent - Used when this specific content is not permitted on the network / shortcode.
30 Message not delivered because the set spend limit is reached Temporary - Used when message fails or is rejected because the subscriber has reached the predetermined spend limit for the current billing period.
31 Message not delivered because the recipient was suspended from premium services Used when the MSISDN is for a valid subscriber on the operator but the message fails or is rejected because the subscriber is unable to be billed, e.g. the subscriber account is suspended (either voluntarily or involuntarily), the subscriber is not enabled for bill-tophone services, the subscriber is not eligible for bill-to-phone services, etc.
33 Message not delivered because of parental lock Used when the subscriber cannot receive adult content because of a parental lock.
34 Message not delivered because age check failure Permanent - Used when the subscriber cannot receive adult content because they have previously failed the age verification process.
35 Message not delivered because age check missing Temporary - Used when the subscriber cannot receive adult content because they have not previously completed age verification.
36 Message not delivered because age check unavailable Temporary - Used when the subscriber cannot receive adult content because a temporary communication error prevents their status being verified on the age verification platform.
37 Message not delivered because recipient is in national Do-Not-Call Register (for example, the Dutch SMS DienstenFilter and Chinese DnD list) The MSISDN is on the national blacklist

SMPP

Clients can use SMPP to deliver and receive mobile terminated (MT) messages, mobile originated (MO) messages and delivery reports (DLR messages) to and from the CM SMS gateway. CM supports SMPP protocol version 3.4.

Delivery receipts

Delivery receipts are sent in the short_message field of a deliver_sm or the message_payload TLV of a data_sm PDU, as per account configuration. In both cases, the message state is available as a message_state TLV attached to the PDU as well as in the actual receipt. Use whichever is more convenient.

Global description

The following format is used:

id:IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII submit date:yyyyMMddHHmmss done date:yyyyMMddHHmmss stat:SSSSSSS err:EEE


The number and order of fields is fixed, and they are separated by a single ASCII space. It is unwise to depend on this, however; for extendibility, you should not assume any number or ordering of fields and accept arbitrary whitespace as separator.

Similarly, though sizes are specified, strings not of fixed length may vary in size -- the specified size only reflects the maximum returned size as currently implemented. In no case will the total message length exceed 255 characters, however.

Field breakdown
Field Size Type Description
id 32 string The message ID allocated to the message by the SMSC when originally submitted.
stat 7 Fixed length string The final status of the message as specified in Table Message state values or ENROUTE for receipts of pending messages.
submit date 14 Fixed length string The time and date at which the short message was sent. Formatted: yyyyMMddHHmmss
done date 14 Fixed length string The time and date at which the short message reached its final state. Formatted: yyyyMMddHHmmss
Message state values
Message state Final message states Description (from SMPP standard) CM specific description
DELIVERED DELIVERD Message is delivered to destination. Message was delivered at the handset.
EXPIRED EXPIRED Message validity period has expired.
DELETED DELETED Message has been deleted. Not used.
UNDELIVERABLE UNDELIV Message is undeliverable. Message was not delivered at the handset.
ACCEPTED ACCEPTD Message is in accepted state (i.e. has been manually read on behalf of the subscriber by customer service). Message has been buffered at the operator network.
UNKNOWN UNKNOWN Message is in an invalid state. Not used.
REJECTED REJECTD Message is in a rejected state. Message was not accepted by the server.

Notable differences with the example format given in the standard:

  • Strings are not zero-terminated but whitespace-separated. As such, no string contains whitespace.
  • The message id is not a 10-digit decimal but a 32-character string.
  • The date specifies a 4-digit year, not a 2-digit one, and includes seconds.
  • The 'sub', 'dlvrd' and 'text' fields are not available.
Single connection

In order to use a single connection to send messages for all operators and tariffs the following proprietary TLVs are supported for both the DELIVER_SM PDUs and the SUBMIT_SM PDUs (please note that the tariff TLV is not yet used for DELIVER_SM PDUs). The "basic unit" of the tariff field is presently cents for all accounts.

Field Size octets Type Description
Parameter tag 2 Integer 0x1401
Length 2 Integer Length of Value part
Value 1-7 C-Octet string(Decimal) MCC/MNC of operator
Field Size octets Type Description
Parameter tag 2 Integer 0x140A
Length 2 Integer Length of Value part
Value 1-6 C-Octet string(Decimal) Tariff in basic unit