NAV Navbar
cURL Ruby

Getting started

Irrelevant headers will be omitted and json pretty-printed for clarity.

To use the Message REST API you need an account. Please get in touch with our friendly support team or your sales contact and you'll be up and running in no time!

Email: kund@genericmobile.se
Phone: 020-31 00 41 International: +46 86016666

Base URL: https://api.genericmobile.se/SmsGateway/api/v1

Messages sent and received with the REST API will be visible in the SMS Web portal.

Authentication

Add Authorization header

curl "https://api.genericmobile.se/SmsGateway/api/v1/" \
  --basic -u Alice:secretPwd
require 'uri'
require 'base64'
require 'net/http'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host: 'api.genericmobile.se',
  path: '/'
)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(
    uri.path,
    { # Headers
      'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}"
    }
  )
end

Example HTTP session

GET / HTTP/1.1
Host: api.genericmobile.se
Authorization: Basic QWxpY2U6c2VjcmV0UHdk

Basic authentication is used for access control, see RFC 7617 for details. All requests must contain an Authentication header with Basic as first parameter followed by a base64-encoded username:password.

401 Unauthorized

Will be returned if your credentials are wrong or you have insufficient privileges.

Send messages

Immediate delivery

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46707659443"],
        "Text": "Hello\nWorld!\uD83D\uDE42"
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
  'Content-Type'  => "application/json"
}

body = {
  'From' => 'Alice',
  'To'   => [ '+46707659443' ],
  'Text' => "Hello\nWorld!\u{1F642}"
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, JSON.generate(body), headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

The send messages feature can be used to send one or more text messages immediately or at a specified date and time. You can combine most of the features described here to your liking.

POST /Message

In its simplest form only From, To and Text are required, see parameters for details.

In the example, +46707659443 will get a new text message from Alice containing two lines and a smiley
Hello
World!😄

HTTP Response

201 Created

A successful request contains a receipt object.

Scheduled delivery

Scheduled delivery

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46707659443"],
        "Text": "Today is tomorrow",
        "BatchJobName": "Future",
        "SendAt": "2019-08-27T15:14:08+01:00"
      }'
require 'json'
require 'base64'
require 'uri'
require 'net/http'
require 'date'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
  'Content-Type'  => "application/json"
}

body = {
  'From' => 'Alice',
  'To' => [ '+46707659443' ],
  'Text' => 'Today is tomorrow',
  'BatchJobName' => 'Future',
  'SendAt' => '2019-08-27T15:14:08+01:00',
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, JSON.generate(body), headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "BatchId": "12345678-abcd-1234-5678-1234567890ab",
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

POST /Message

By specifying SendAt it's possible to schedule messages to be sent at a specified date and time. You may optionally set BatchJobName for easy filtering and follow up with the SMS Web portal.

HTTP Response

201 Created

A successful request contains a receipt object with the BatchId set to a unique ID that could be used to delete this batch.

Delete a batch

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/Message/12345678-abcd-1234-5678-1234567890ab \
  --basic -u Alice:secretPwd
204 No Content

DELETE /Message/{BatchId}

Where {BatchId} is from the Scheduled delivery response. If the batch have not yet been sent, deleting it will prevent it from ever doing so.

HTTP Response

204 No Content

The scheduled delivery was successfully deleted.

404 Not Found

The {BatchId} was not found/already deleted.

Limited validity period

Limited validity period

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "2FA",
        "To": ["+46707659443"],
        "Text": "Security code: 123456",
        "ValidityPeriodMinutes": 5
      }'
require 'json'
require 'base64'
require 'uri'
require 'net/http'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

body = {
  'From' => '2FA',
  'To' => [ '+46707659443' ],
  'Text' => 'Security code: 123456',
  'ValidityPeriodMinutes' => 5
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

POST /Message

Text messages can't be delivered to mobile phones that are turned off or by other means unreachable. However messages are stored and new delivery attempts are made for a certain time, default is 4320 minutes (3 days). After this period the message is dropped. You may set ValidityPeriodMinutes to a lower value in cases where the message bear no meaning if not delivered within a period of time.
The validity period starts when the message is sent.

HTTP Response

201 Created

A successful request contains a receipt object.

Flash message

Flash message

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46707659443"],
        "Text": "This is an urgent message",
        "Flash": true
      }'
require 'json'
require 'base64'
require 'uri'
require 'net/http'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

body = {
  'From' => 'Alice',
  'To' => [ '+46707659443' ],
  'Text' => 'In your face',
  'Flash' => true
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

POST /Message

A flash message is delivered and shown directly on the mobile device display. The message will be shown until the receiver discards it and the message will not be stored by default. Enable this feature by setting Flash to true, however this feature can not be combined with SendAt.
Flash messages may be suitable for important or sensitive information.

HTTP Response

201 Created

A successful request contains a receipt object.

Message with text parameters

Text parameters

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Boss",
        "To": ["+46707659443", "+46768920857"],
        "Text": "Hi {1}, you look {2}!",
        "TextParameters": [
          ["Bob", "tired"],
          ["Alice", "great"]
        ]
      }'
require 'json'
require 'base64'
require 'uri'
require 'net/http'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

body = {
  'From' => 'Boss',
  'To' => [
    "+46707659443",
    "+46768920857"
  ],
  'Text' => "Hi {1}, you look {2}!",
  'TextParameters' => [
    [ 'Bob', 'tired' ],
    [ 'Alice', 'great' ]
  ]
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "MessageId": [
    "deadc0de-2bad-c4fe-feed-beefca1ff00d",
    "deadc0de-2bad-c4fe-feed-beefca1ff001"
  ]
}

POST /Message

Text parameters can be used to personalize the message for each receiver phone number. This is done iteratively by replacing {1}, {2}, {3}, etc. in Text with the corresponding strings from the TextParameters array. The first phone number in the To array will use the first replacement array from TextParameters and so forth. Make sure the TextParameters array have as many sub-arrays as the To array have phone numbers.

In the example, +46707659443 will receive Hi Bob, you look tired! where as +46768920857 will get Hi Alice, you look great!.

HTTP Response

201 Created

A successful request contains a receipt object.

Parameters

Parameter Required Type Default Description
From Yes String - Phone number or an alphanumeric string1.
To Yes Array(1..1000) of Strings - List of recipient phone numbers.
Text Yes String - The message body.
DeliveryReportUrl No String(9..255) null http(s) URL for receiving delivery reports, if null or omitted no delivery report will be sent.
BatchJobName No String(1..50) Generated name A name tag for a scheduled delivery.
SendAt No ISO-8601 DateTime Now Max three months from now. Passed DateTimes will be sent immediately.
ValidityPeriodMinutes No Integer 4320 The validity period of the message.
Flash No Boolean False The message will be sent as flash SMS.
TextParameters No Array of Arrays of Strings Empty Array Strings to insert into message body. The length of the outer Array must match the length of the Text Array.
DynamicAnswer No Boolean False Enable the Dynamic Answer feature.
Reference No String(0..255) null A user defined reference to associate incoming messages with this messages. See Dynamic Answer.

1 An alphanumeric string may contain A-Ö, a-ö, 0-9 or any of the special characters "#%&'()*+-./?, max 11 characters. However some operators are not able to handle swedish charachters and becasue of that we recommend you to only use A-Z, a-z, 0-9. When using the Dynamic Answer feature, From should match the name or number of a pool.

Receipt object

Receipt object example

{
  "BatchId": "12345678-abcd-1234-5678-1234567890ab",
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}
Key Description Type
MessageId Array of Unique IDs, one for each receiver phone number the message is destined for Array
BatchId Present when SendAt is used to create a scheduled batch String

Delivery Report

Delivery reports are used to find out whether a message has been delivered or not. The most efficient way is to specify a callback URL for us to send/push the delivery report to as soon as we get it. But we also provide an API endpoint for you to poll for updates.

Delivery reports with push

Enable delivery report when sending a message

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46707659443"],
        "Text": "Hello",
        "DeliveryReportUrl": "https://api.example.se/DR"
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
  'Content-Type'  => "application/json"
}

body = {
  'From'              => 'Alice',
  'To'                => [ '+46707659443' ],
  'Text'              => "Hello\nWorld!\u{1F642}",
  'DeliveryReportUrl' => 'https://api.example.se/DR'
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, JSON.generate(body), headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

Turn on this feature by specifying DeliveryReportUrl when sending a message. In case there are network issues or your endpoint doesn't acknowledge the delivery report we will make retry a couple of times during a 30 minute period. After that you'll have to poll for the delivery reports.

HTTP Request

Example HTTP session with DeliveryReportUrl set to https://api.example.se/DR,

POST /DR HTTP/1.1
Host: api.example.se
Content-Type: application/json

{
  "MessageId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
  "StatusTime": "2018-01-19T04:14:08+01:00",
  "Status": "Delivered"
}

We will make a POST request containing a application/json encoded delivery report object. The example http session shows how it may look like.

HTTP Response

200 OK

Your endpoint should acknowledge the delivery report by responding 200 OK.

Delivery reports with poll

Get message status

curl https://api.genericmobile.se/SmsGateway/api/v1/Message/deadc0de-2bad-c4fe-feed-beefca1ff00d \
  --basic -u Alice:secretPwd
require 'json'
require 'base64'
require 'uri'
require 'net/http'

message_id = 'deadc0de-2bad-c4fe-feed-beefca1ff00d' 

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     File.join('/SmsGateway/api/v1/Message', message_id)
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

delivery_report = nil

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(uri.path, headers) do |response|
    delivery_report = JSON.parse(response.read_body)
  end
end

puts JSON.pretty_generate(delivery_report)
200 OK
{
  "MessageId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
  "StatusTime": "2018-12-06T15:57:08+01:00",
  "Status": "Delivered"
}

GET /Message/{MessageId}

See how a specific message is doing. Note that all messages will start off with Status = Sending, even messages scheduled for later delivery. The {MessageId} is the unique ID of a sent message found in the receipt object.

HTTP Response

200 OK

The response is a delivery report object.

Delivery report object

Example delivery report

{
  "MessageId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
  "StatusTime": "2018-12-06T15:57:08+01:00",
  "Status": "Failed",
  "Reason": "Invalid destination number"
}
Key Type Description
MessageId String The Id of the requested message.
StatusTime ISO-8601 DateTime When the status was last updated.
Status String Sending -> Sent -> Delivered / Failed.
Reason String Description of problem, only present if Status = "Failed".

Receive messages

List your inboxes

curl https://api.genericmobile.se/SmsGateway/api/v1/Inbox \
  --basic -u Alice:secretPwd
200 OK
{
  "Inboxes": [
    {
      "Inbox": "+46101234567",
      "NotificationUrl": "https://example.com/inboxNotification"
    }
  ]
}

Just as a mobile phone get its messages delivered to an inbox, it's possible to configure one or more phone numbers where you can receive messages. Those inboxes are visible on the SMS Web portal but could also be queried by the API. The phone numbers are provided by Generic and associated with your account. You can retrieve the list in inboxes as the example shows.

Setting URL for push messaging

Setting NotificationURL for an inbox

curl -X PUT https://api.genericmobile.se/SmsGateway/api/v1/Inbox/46707659443 \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "NotificationURL": "https://example.com/inboxNotification"
      }'
require 'json'
require 'base64'
require 'uri'
require 'net/http'

inbox_number = "46101234567"

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     File.join('/SmsGateway/api/v1/Inbox', 'inbox_number')
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

body = {
  'NotificationURL': 'https://example.com/inboxNotification'
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_put(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end

By specifying a NotificationURL on the Inbox we will send all incoming messages to that URL. This NotificationURL could be set with the API, as shown in the example, or with the SMS Web portal. If the notification endpoint isn't available new delivery attempts will be made every 15 minutes for 72 hours.

PUT /Inbox/{phoneNumber}

Where {phoneNumber} is the telephone number of the inbox for which the URL shall be set for.

Parameter Description Type
NotificationURL URL received messages are sent to String

Receive messages with push

Example of inbox notification

POST /inboxNotification HTTP/1.1
Host: api.example.se
Content-Type: application/json
Connection: Keep-Alive
Expect: 100-continue

[
  {
    "Id": 12345678,
    "From": "+46707659443",
    "To": "+46101234567",
    "Text": "You've got a new message",
    "ReceiveTime": "2018-12-10T11:42:55+01:00"
  }
]

If a NotificationURL is specified we will send/push any incoming message to that URL as soon as it arrives to the inbox. This is the most efficient and preferred way to retrieve messages. The POST request contains an array of up to 100 Message objects.

Similar to how we push delivery reports it's important to respond with a 2xx HTTP Status code to let us know you've successfully retrieved the message(s).

Fetch messages

Example of message polling

curl "https://api.genericmobile.se/SmsGateway/api/v1/Inbox/46101234567?beginid=3412266&newer=true&limit=5" \
  --basic -u Alice:secretPwd
require 'json'
require 'base64'
require 'uri'
require 'net/http'

inbox_number = "46101234567"

query = {
  'BeginId' => 3412266,
  'Newer' => true, 
  'Limit' => 5
}

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     File.join('/SmsGateway/api/v1/Inbox', inbox_number),
  query:    URI.encode_www_form(query)
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(uri.path, headers) do |response|
    puts response.read_body
  end
end
200 OK
{
  "Inbox": "+46101234567",
  "Messages": [
    {
      "Id": 3412411,
      "From": "+46707659443",
      "To": "+46101234567",
      "Text": "Räksmörgås",
      "ReceiveTime": "2018-12-10T11:32:02+01:00"
    },
    {
      "Id": 3412507,
      "From": "+46707659443",
      "To": "+46101234567",
      "Text": "Hello 😎",
      "ReceiveTime": "2018-12-10T11:42:55+01:00"
    }
  ]
}

Fetching messages support pagination by the use of Limit, BeginId and Newer which are passed in as URI parameters in the GET request.

GET /Inbox/{PhoneNumber}

Where {PhoneNumber} is the telephone number of the inbox.

Parameter Required Type Default Description
Limit No Integer 100 Max number of received messages in one response.
BeginId No Integer Max Id to start from (will not be included).
Newer No Boolean false Get newer or older messages than the BeginId.

The sort order is based on the Id and descending as default. Setting Newer=true will reverse the order.

HTTP Response

200 OK

Key Type Description
Inbox String Phone number which the message(s) has been received on.
Messages Array Array of message objects.

Dynamic Answer

Send two messages with Dynamic Answer enabled

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Pool-1",
        "To": ["+46707659443"],
        "Text": "Rate our support! Answer 1-5 where 5 is awesome",
        "DynamicAnswer": true,
        "Reference": "support"
      }'
201 Created
{
  "MessageId": [ "deadc0de-2bad-c4fe-feed-beefca1ff001" ]
}
curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Pool-1",
        "To": ["+46707659443"],
        "Text": "Would you recommend us to a friend? Answer 1-5 where 5 is absolutely",
        "DynamicAnswer": true,
        "Reference": "friend"
      }'
201 Created
{
  "MessageId": [ "deadc0de-2bad-c4fe-feed-beefca1ff002" ]
}

An answer from +46707659443 mapped to the support question

[
  {
    "Id": 3425333,
    "From": "+46707659443",
    "To": "+46101234567",
    "Text": "5",
    "ReceiveTime": "2018-12-11T13:30:52.903+01:00",
    "Reference": "support"
  }
]

The Dynamic Answer feature allows received messages to be associated with sent messages.

This is accomplished by dynamically selecting a sender phone number from a pool of numbers in order to create a session with the receiver. This number pool needs to be configured for you by Generic, but once in place you may enable this feature by setting DynamicAnswer to true.
Set a Reference value when sending a message and the same reference value will be present when receiving messages, allowing you to treat incoming messages as answers to what you sent out.

You may have multiple pools of numbers, thus you need to state which pool to use by setting From to the name or number of the pool.

Example explained Someone has just been in contact with your support and you'd like to get some feedback; How the support experience was and How likely you'd be recommended to a friend. Based on that you send two SMS, with one question each, to the customers mobile phone. To maximize the response rate, it must be easy for the user to respond. Here a single digit will suffice, and Dynamic Answer will keep track of which question a response belongs to.

POST /Message

Besides the required parameters needed to send a message you should set DynamicAnswer and preferably also Reference.

HTTP Response

201 Created

A successful request contains a receipt object.

Received answers

Answers on messages sent with the Dynamic Answer feature may be received as usual via either push or poll. Such messages have the Reference parameter set in the message object. The To parameter shows which of the pool numbers was used to send the initial message.

Message Object

Key Type Description
Id Integer Unique id for the received message.
From String Phone number which the message was sent from.
To String Phone number which the message was sent to.
Text String Message body.
ReceivedTime ISO-8601 DateTime When the message was received by the service.
Reference String Omitted if null, see DynamicAnswer.

User Administration

Accounts are divided into two different types, admin users and regular users. Admin users are able to create and modify regular users and provide them with a phone number for receiving messages. Admin users are also able to fetch statistics for a regular user, for example the number of sent SMS during a specific time period.
A locked account can't access the API nor log into our SMSWeb portal.

Create a user

Create the user Bob

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/User \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "UserID": "Bob",
        "Password": "bobsNewPassword",
        "Description": "My uncle"
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/User'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

body = {
  'UserID'   => 'Bob',
  'Password' => 'bobsNewPassword',
  'Description' => 'My uncle'
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "UserID": "Bob",
  "Description": "My uncle",
  "Locked": false
}

A new regular user is created by using at least UserID and Password.

POST /User

Note that UserID must be globally unique.

HTTP Response

201 Created

The user was successfully created, the response contains a user object.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Message": "A user with this name already exists!"}

List/get users

List users

curl https://api.genericmobile.se/SmsGateway/api/v1/User \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/User'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(uri.path, headers) do |response|
    puts response.read_body
  end
end
200 OK
[
  {
    "UserID": "Alice",
    "Description": "",
    "Locked": false
  },
  {
    "UserID": "Bob",
    "Description": "My uncle",
    "Locked": true,
    "IpRestrictions": ["127.0.0.1", "192.168.0.0/24"]
  }
]

Admin users may list all users and their properties.

GET /User

HTTP Response

200 OK

The response contains an array of user object(s).

It's also possible for a admin user to list properties of a given user.

GET /User/{UserId}

Where {UserId} is the unique identification of a regular user.

HTTP Response

200 OK

The response contains a single user object.

Delete user

Delete Bob

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/User/Bob \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/User/Bob'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(Net::HTTP::Delete.new(uri.path, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

DELETE /User/{UserId}

Where {UserID} is the unique identification of a regular user.

HTTP Response

204 No Content

The user was successfully deleted.

404 Not Found

Either the user don't exists or you don't have permission to delete the user.

Update user

Update Bob's IpRestrictions parameter

curl -X PUT https://api.genericmobile.se/SmsGateway/api/v1/User/Bob/IpRestrictions \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '["127.0.0.1", "192.168.0.0/24"]'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/User/Bob/IpRestrictions'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

body = [ "127.0.0.1", "192.168.0.0/24" ]
headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_put(uri.path, json_body, headers)) do |response|
    puts response.read_body
  end
end
200 OK
{
  "UserID": "Bob",
  "Description": "My uncle",
  "Locked": false,
  "IpRestrictions": ["127.0.0.1", "192.168.0.0/24"]
}

A regular user can be updated by an admin user. All but the user name may be updated.

PUT /User/{UserId}/{Attribute}

Where {UserId} is the unique identification of a regular user and {Attribute} the parameter to update, Description, Password, IpRestrictions or Locked.

HTTP Response

200 OK

For all attributes except Password.
The user was successfully updated, the response contains a user object.

204 No Content

When updating the password no content is returned to indicate a successful request.

Parameters

Parameter Required Type Default Description
UserID Yes String - The name of the user a-z, A-Z, 0-9, max 15 characters.
Password No String - Password of the regular user (7-bit ASCII 6-15 characters).
Description No String Empty string Description of the regular user.
IpRestrictions No Array of Strings null A list of IP-addresses and/or sub-networks from which the regular user may connect to the service. If not set no restrictions apply and the user may connect from anywhere.
Locked No Boolean false Open or locked account.

User Object

Key Type Description
UserID String Identification of a the user created.
Description String Description of the regular user, max 50 characters.
Locked Boolean Status of the user.
IpRestrictions Array of Strings IP-addresses and/or sub-networks from which the user may connect to the service. Omitted if null.

Contacts Administration

With the contact administration api function you are able to create, update and delete individual and group contacts visible in the SMS Web portal. With an Admin user it´s also possible to share contacts with regular users.

Create individual

Create the individual Bob

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Individuals \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "Name": "Bob",
        "Number": "+46707659443",
        "IsShared": false
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Individuals'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

body = {
  'Name'   => 'Bob',
  'Number' => '+46707659443',
  'IsShared' => false
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "Id": 5678,
  "Name": "Bob",
  "Number": "+46707659443",
  "IsShared": false
}

To create a new individual send a POST request with an individual object containing at least Name and Number. The Id cannot be set, it will be generated by the API and any given value will be ignored.

POST /Contacts/Individuals

HTTP Response

201 Created

The individual was successfully created, the response contains an individual object.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Message": "Validation failed - Number must be in international format"}

List/get individuals

List all individuals

curl https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Individuals \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Individuals'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
} 

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(uri.path, headers) do |response|
    puts response.read_body
  end
end
200 OK
[
  {
    "Id": 4321,
    "Name": "Alice",
    "Number": "+46101234567",
    "IsShared": false
  },
  {
    "Id": 5678,
    "Name": "Bob",
    "Number": "+46707659443",
    "IsShared": false
  }
]

A list of all individuals can be retrieved.

GET /Contacts/Individuals

HTTP Response

200 OK

The response contains an array of individual object(s).

It's also possible to retrieve a single individual.

GET /Contacts/Individuals/{Id}

Where {Id} is the identifier of an individual.

HTTP Response

200 OK

The response contains a single individual object.

Delete individual

Delete user 5678

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Individuals/5678 \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Individuals/5678'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(Net::HTTP::Delete.new(uri.path, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

DELETE /Contacts/Individuals/{Id}

Where {Id} is the identifier of an individual.

HTTP Response

204 No Content

The contact was successfully deleted.

404 Not Found

Either the individual doesn't exist or you don't have permission to delete it.

Update individual

Update Bob's Number

curl -X PUT https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Individuals/5678/Number \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '+46707659443'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Individuals/5678/Number'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
  'Content-Type' => "application/json",
}

body = "+46707659443"
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_put(uri.path, json_body, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

An individual can be updated.

PUT /Contacts/Individuals/{Id}/{Attribute}

Where {Id} is the identifier of an individual and {Attribute} the individual object parameter to update, Name, Number or IsShared. The parameter value shall be placed in the request body.

HTTP Response

204 No Content

The individual was successfully updated.

Individual Object

Parameter Required Type Default Description
Id No Int - The individual identifier.
Name Yes String - Name of individual (max 50 characters).
Number Yes String - Phone number to the individual in international format.
IsShared No Boolean false Admin users can create and share contacts with regular users.

Create group

Create the group MyFriends

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "Name": "MyFriends",
        "Members": [4321, 5678],
        "IsShared": false
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

body = {
  'Name'   => 'MyFriends',
  'Members' => [4321, 5678],
  'IsShared' => false
}

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
201 Created
{
  "Id": 6789,
  "Name": "MyFriends",
  "Members": [4321, 5678],
  "IsShared": false
}

To create a new group send a POST request with a group object containing at least Name and Members. Two groups are not allowed to have the same Name. Members is an array of individual identifiers, missing or duplicate identifiers are silently ignored. The Id cannot be set, it will be generated by the API and any given value will be ignored.

POST /Contacts/Groups

HTTP Response

201 Created

The group was successfully created, the response contains a group object.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Message": "Group name must be unique"}

List/get groups

List all groups

curl https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_get(uri.path, headers) do |response|
    puts response.read_body
  end
end
200 OK
[
  {
    "Id": 6789,
    "Name": "MyFriends",
    "Members": [4321, 5678],
    "IsShared": false
  },
  {
    "Id": 7890,
    "Name": "OurCustomers",
    "Members": [123, 456],
    "IsShared": false
  }
]

A list of all groups can be retrieved.

GET /Contacts/Groups

HTTP Response

200 OK

The response contains an array of group object(s).

It's also possible to retrieve a single group.

GET /Contacts/Groups/{Id}

Where {Id} is the identifier of a group.

HTTP Response

200 OK

The response contains a single group object.

Delete group

Delete group 7890

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups/7890 \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups/7890'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(Net::HTTP::Delete.new(uri.path, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

DELETE /Contacts/Groups/{Id}

Where {Id} is the identifier of a group.

HTTP Response

204 No Content

The group was successfully deleted.

404 Not Found

Either the group doesn't exist or you don't have permission to delete it.

Update group

Update MyFriends's Members

curl -X PUT https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups/6789/Members \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '[123, 456]'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups/6789/Members'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
  'Content-Type' => "application/json",
}

body = [123, 456]
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_put(uri.path, json_body, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

A group can be updated.

PUT /Contacts/Groups/{Id}/{Attribute}

Where {Id} is the identifier of a group and {Attribute} the group object parameter to update, Name, Members or IsShared. The parameter value shall be placed in the request body.

When updating Members all previous members are deleted, invalid identifiers are silently ignored.

HTTP Response

204 No Content

The group was successfully updated.

Add group members

Add two members to the group MyFriends

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups/6789/Members \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '[123, 456]'
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups/6789/Members'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

body = [123, 456]

headers['Content-Type'] = 'application/json'
json_body = JSON.generate(body)

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request_post(uri.path, json_body, headers) do |response|
    puts response.read_body
  end
end
204 No Content

To add members to a group send a POST request with an array of identifiers to add.

POST /Contacts/Groups/{Id}/Members

HTTP Response

204 No Content

The members were successfully added, invalid identifiers are silently ignored.

Delete group member

Delete member 123 from group 7890:

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/Contacts/Groups/7890/Members/123 \
  --basic -u Alice:secretPwd
require 'base64'
require 'uri'
require 'net/http'
require 'json'

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Contacts/Groups/7890/Members/123'
)

headers = {
  'Authorization' => "Basic #{Base64.strict_encode64(uri.userinfo)}",
}

Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(Net::HTTP::Delete.new(uri.path, headers)) do |response|
    puts response.read_body
  end
end
204 No Content

DELETE /Contacts/Groups/{GroupId}/Members/{IndividualId}

Where {GroupId} is the identifier of the group from which the individual with identifier `{IndividualId} is to be deleted.

HTTP Response

204 No Content

The member was successfully deleted from the group.

404 Not Found

Either the group or the individual doesn't exist or you don't have permission to delete it.

Group Object

Parameter Required Type Default Description
Id No Int - The group identifier.
Name Yes String - Name of group (max 50 characters).
Members Yes Array of int - Array of individual identifiers.
IsShared No Boolean false Admin users can create and share contacts with regular users.

Statistics

Example statistics

curl "https://api.genericmobile.se/SmsGateway/api/v1/Statistics/Alice/Sent?start=2018-12-01&end=2018-12-24T15:00:00%2B01:00" \
  --basic -u Alice:secretPwd
200 OK
{
  "FirstMessage": "2018-10-23T13:11:59+02:00",
  "LastMessage": "2018-12-11T13:30:13+01:00",
  "Sent": 20,
  "Delivered": 19,
  "Failed": 1,
  "Unknown": 0
}

An admin user may obtain statistics of SMS sent during a given time period.

GET /Statistics/{UserId}/Sent?start={DateTime}&end={DateTime}

Where {UserId} is the identification of a user. Both start and end are optional. Please note that you may need to URL encode the {DateTime} as seen in the example. If no timezone is given CET/CEST is assumed (local timezone in Sweden).

HTTP Response

200 OK

A successful response holds this statistics object

Key Type Description
FirstMessage ISO-8601 DateTime Date and time of the first sent SMS within the given timespan
LastMessage ISO-8601 DateTime Date and time of the last sent SMS within the given timespan
Sent Integer Number of sent SMS.
Delivered Integer Number of delivered SMS.
Failed Integer Number of failed, not delivered SMS.
Unknown Integer Number of failed, not delivered, SMS due to unknown reason.

Errors

HTTP response codes

Success

HTTPS Code Status Description
200 OK Successful request.
201 Created Successful request, content was created.
204 No Content Successful request, no content will be returned.

Errors

Example of error responses with body

400 Bad Request
{
  "Message": "Failed to update user password"
}

400 Bad Request
{
  "Code": 200,
  "Description": "Parameter \"To[0]\" must be an international phone number"
}

Most error responses from the API will include a Message or Description property with more details of what went wrong.

Client

HTTPS Code Status Description
400 Bad request Something in the request is missing or wrong.
401 Unauthorized Authentication failed.
403 Forbidden The request is correct but cannot be performed.
404 Not found Resource not found.
405 Method not allowed The method specified is not allowed for the resource.
406 Not Acceptable Content generated is not matched with the Accept header.
411 Length Required Content-Length header is missing or wrong.
415 Unsupported Media Type Content-Type header is missing or wrong.
429 Too many requests Too many requests within the specified time slot. The HTTP header Retry-After specifies the number of seconds to wait before the next POST request can be made.

Server Errors

HTTPS Code Status Description
500 Internal Server Error Server could not process the request due to internal error.
502 Bad Gateway Invalid response or could not reach upstream server or application pool.
503 Service unavailable Server is currently unavailable or down for maintenance.

Format and Encoding

Message body

Messages sent with the REST API are divided into one or more SMSs. The message body, which is represented by the Text parameter, is encoded using UTF-8. When only GSM characters1 are used the maximum size of a single SMS is 160 characters. For longer messages the API will automatically split the text into multiple SMSs, each with a maximum of 153 characters. When characters not represented in the GSM 03.38 are used, the message body will be encoded using UCS-2 (UTF-16 Big Endian) and the maximum size of each SMS is 70 characters. The API will split the message into several SMSs of maximum 67 characters.

GSM 03.38 character set

Each character is encoded to 7 bits (0x00..0x7F)

0x 1x 2x 3x 4x 5x 6x 7x
x0 @ Δ SP 0 ¡ P ¿ p
x1 £ _ ! 1 A Q a q
x2 $ Φ " 2 B R b r
x3 ¥ Γ # 3 C S c s
x4 è Λ ¤ 4 D T d t
x5 é Ω % 5 E U e u
x6 ù Π & 6 F V f v
x7 ì Ψ ' 7 G W g w
x8 ò Σ ( 8 H X h x
x9 Ç Θ ) 9 I Y i y
xA LF Ξ * : J Z j z
xB Ø ESC + ; K Ä k ä
xC ø Æ , < L Ö l ö
xD CR æ - = M Ñ m ñ
xE Å ß . > N Ü n ü
xF å É / ? O § o à

Phone number formats

All phone numbers should be given in international format, see E.164 and NANP.

MSISDNs (phone numbers) should start with +, e.g. +46707659443. If part of an URI the + shall be omitted, e.g. 46707659443.