NAV
shell ruby

Getting started

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

Authentication with API key

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  -H 'Authorization: Bearer 90be0b2c-b218-4070-a890-152821090464' \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46701740605"],
        "Text": "Hello\nWorld!\uD83D\uDE42"
      }'
require 'base64'
require 'uri'
require 'net/http'
require 'json'


uri = URI::HTTPS.build(
  apikey: '90be0b2c-b218-4070-a890-152821090464',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Message'
)

headers = {
  'Authorization' => "Bearer #{uri.apikey}",
  'Content-Type'  => "application/json"
}

body = {
  'From' => 'Alice',
  'To'   => [ '+46701740605' ],
  '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"]
}

Access can be granted using an API key. For this method, all requests must contain an Authorization header with Bearer as the first parameter, followed by the API key. All administration of API keys is managed via our customer platform.

Basic authentication

For legacy reasons basic authentication using username and password are also supported, see RFC 7617 for details. All requests must contain an Authentication header with Basic as first parameter followed by a base64-encoded username:password. If username or password contains non-ASCII characters, use UTF-8 encoding before the base64-encoding.

401 Unauthorized

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

Send messages

Immediate delivery

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

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "Alice",
        "To": ["+46701740605"],
        "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'   => [ '+46701740605' ],
  '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, +46701740605 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.

Throttling

By default we accept 40 messages/second. If you're sending more you'll get throttled (receive a 429 Too many requests response). It's important that your client can handle this properly. We recommend you queue up messages on your side and don't sent faster than your account is configured for. Or at least implement some form of re-try in case of 429. It might be an alternative to use scheduled delivery in order for you to batch multiple messages. In this case we're taking care of the rate limit for you.

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": ["+46701740605"],
        "Text": "Today is tomorrow",
        "BatchJobName": "Future",
        "SendAt": "2024-09-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' => [ '+46701740605' ],
  'Text' => 'Today is tomorrow',
  'BatchJobName' => 'Future',
  'SendAt' => '2024-09-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": ["+46701740605"],
        "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' => [ '+46701740605' ],
  '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": ["+46701740605"],
        "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' => [ '+46701740605' ],
  '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": ["+46701740605", "+46701740606"],
        "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' => [
    "+46701740605",
    "+46701740606"
  ],
  '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, +46701740605 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 String1 - Phone number, alphanumeric sender or a Dynamic Answer pool.
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 one year 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.
ForceVoice No Boolean False If True, the recipient will be called and the Text read out loud using speech synthesis.
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 Tag the message with a custom reference. Usable when dissecting the message log or associate incoming messages when using Dynamic Answer.

1 A phone number should be given in international format (leading + sign). An alphanumeric sender may contain A-Ö, a-ö, 0-9 or any of the special characters "#%&'()*+-./?, max 11 characters. However some operators are not able to handle Swedish characters and because of that we recommend you to only use A-Z, a-z, 0-9.

Receipt object

Receipt object example

{
  "BatchId": "12345678-abcd-1234-5678-1234567890ab",
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}
Key Description Type
MessageId Array of Message IDs, one for each receiver phone number the message is destined for and in the same order. 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": ["+46701740605"],
        "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'                => [ '+46701740605' ],
  '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 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": "2020-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": "2020-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": "2020-12-06T15:57:08+01:00",
  "Status": "Failed",
  "ErrorCode": 52,
  "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.
ErrorCode Int ErrorCode, only present if Status = "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": "+46846500400",
      "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/46701740605 \
  --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 = "46846500400"

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. Note that it's only the administrator that can set the NotificationURL.

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": "+46701740605",
    "To": "+46701740606",
    "Text": "You've got a new message",
    "ReceiveTime": "2020-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/46846500400?beginid=3412266&newer=true&limit=5" \
  --basic -u Alice:secretPwd
require 'json'
require 'base64'
require 'uri'
require 'net/http'

inbox_number = "46846500400"

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": "+46846500400",
  "Messages": [
    {
      "Id": 3412411,
      "From": "+46701740605",
      "To": "+46846500400",
      "Text": "Räksmörgås",
      "ReceiveTime": "2020-12-10T11:32:02+01:00"
    },
    {
      "Id": 3412507,
      "From": "+46701740605",
      "To": "+46846500400",
      "Text": "Hello 😎",
      "ReceiveTime": "2020-12-10T11:42:55+01:00"
    }
  ]
}

Example 429 Too Many Requests

HTTP/2 429
content-type: application/json
retry-after: 3
{
    "description": "Quota exceeded. Maximum allowed: 1 per 5s. Please try again in 3 second(s)."
}

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.

429 Too Many Requests

Clients are allowed to fetch messages once every 5 seconds. If multiple requests are made within this time frame, the API will respond with HTTP status code 429 Too Many Requests.

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": ["+46701740605"],
        "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": ["+46701740605"],
        "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 +46701740605 mapped to the support question

[
  {
    "Id": 3425333,
    "From": "+46701740605",
    "To": "+46846500400",
    "Text": "5",
    "ReceiveTime": "2020-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",
        "Name": "Bob Smith",
        "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',
  'Name' => 'Bob Smith',
  '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",
  "Name": "Bob Smith",
  "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": "Alice the kitten",
    "Name": "",
    "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",
  "Name": "",
  "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, Name, Password, IpRestrictions or Locked.

HTTP Response

200 OK

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.

User Parameters

Parameter Required Type Default Description
UserID Yes String - Identification of the user a-z, A-Z, 0-9, max 191 characters.
Password Yes String - Password of the regular user (7-bit ASCII 6-191 characters).
Name No String Empty string First- and lastname of the user, max 50 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.
Name String First- and lastname of the user.
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": "+46701740605",
        "IsShared": false,
        "Groups" => [123]
      }'
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' => '+46701740605',
  '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": "+46701740605",
  "IsShared": false,
  "Groups": []
}

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. By providing the optional Groups parameter you can assign group membership directly directly on create.

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": "+46701740606",
    "IsShared": false
  },
  {
    "Id": 5678,
    "Name": "Bob",
    "Number": "+46701740605",
    "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 '+46701740605'
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 = "+46701740605"
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.
Groups No List [] List of GroupIds (integers). Only used when creating an individual.

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.

Stop list Administration

The Stop list feature enables authenticated users to manage a list of phone numbers, effectively preventing SMS messages from being sent to these numbers. This provides detailed information on how to interact with the Stop list API, including adding, retrieving and deleting numbers from the list. Users have exclusive control over their own stop list, with no access to manage others' lists.

Add number to stop list

Add number to stop List

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/Stoplist/Alice \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "Number": "+46701740605",
        "Description": "SMS-free zone.",
      }
require 'base64'
require 'uri'
require 'net/http'
require 'json'

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

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

body = {
  'Number' => '+46701740605',
  'Description' => 'SMS-free zone.'
}

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": "Alice",
  "Number": "+46701740605",
  "Description": "SMS-free zone.",
  "CreatedAt": "2020-01-19T09:36:14.2426241Z"
}

POST /Stoplist/{UserId}

To add a number to the stop list, submit a POST request containing the number along with an optional description. The API automatically manages UserId and CreatedAt, with Number1 being the only required field.

HTTP Response

201 Created

The number was successfully added to the stop list. The response body includes a Stoplist object.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Number": "Validation failed - Parameter \"Number\" must be an international phone number."}

409 Conflict

When attempting to add a number to the stop list, if the number already exists within the list, the API will respond with a status code of 409. This indicates a conflict with the current state of the resource, specifically that the number being added is already present in the user's stop list.

Retrieving Numbers from the Stop list

To list all numbers in your stop list or retrieve a specific number, use the GET method.

List All Numbers

Example request

curl -X GET "https://api.genericmobile.se/SmsGateway/api/v1/Stoplist/Alice?Limit=1234&offset=5"\
  --basic -u Alice:secretPwd \
require 'json'
require 'base64'
require 'uri'
require 'net/http'

query = {
  'Limit' => 1234, 
  'offset' => 5
}

uri = URI::HTTPS.build(
  userinfo: 'Alice:secretPwd',
  host:     'api.genericmobile.se',
  path:     '/SmsGateway/api/v1/Stoplist/Alice?Limit=1234&offset=5'
)

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",
    "Number": "+46701740605",
    "Description": "SMS-free zone.",
    "CreatedAt": "2020-01-19T09:36:14.2426241Z"
  },
  {
    "UserId": "Alice",
    "Number": "+46701740606",
    "Description": "SMS-free zone.",
    "CreatedAt": "2020-01-19T09:36:14.2426241Z",
  }
]

GET /Stoplist/{UserId}

This endpoint enables the retrieval of a list of phone numbers added to a stop list, with a maximum limit of 10 000 records per request to ensure efficient data management. To accommodate large datasets, pagination is supported through the use of limit and offset parameters.

HTTP Response

200 OK

The response will consist of an array of Stoplist object from the stop list, adhering to the specified range.

Retrieve a Specific Number

GET /Stoplist/{UserId}/{Number}

HTTP Response

200 OK

The response will contain a single Stoplist object

404 Not Found

The number specified in the URI is not included in the stop list.

Delete number

Delete number from stop list

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

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

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

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

DELETE /Stoplist/{UserId}/{Number}

The Number specified in the URI is the one you wish to remove from your list.

HTTP Response

204 No Content

The number in the stop list was successfully deleted.

404 No Content

The number doesnt't exist in the authenticated user's stop list.

Stoplist Object

Parameter Type Default Description
UserId String Authenticated user Identification of the user a-z, A-Z, 0-9, max 191 characters.
Number1 String - Phone number in international format
Description String Empty string Optional description of the number in the stop list.
CreatedAt ISO-8601 DateTime Now When the number was added to the stop list.

1 Parameter \"Number\" must be an international phone number.

Statistics

Example statistics

curl "https://api.genericmobile.se/SmsGateway/api/v1/Statistics/Alice/Sent?start=2020-12-01&end=2020-12-24T15:00:00%2B01:00" \
  --basic -u Alice:secretPwd
200 OK
{
  "FirstMessage": "2020-10-23T13:11:59+02:00",
  "LastMessage": "2020-12-11T13:30:13+01:00",
  "Sent": 66,
  "Delivered": 61,
  "Failed": 1,
  "Unknown": 4,
  "Countries":
  [
    {
      "Name": "Sweden",
      "CountryCode": "+46",
      "Sent": 56,
      "Delivered": 51,
      "Failed": 1,
      "Unknown": 4,
      "FixedLine": {
        "Sent": 50,
        "Delivered": 49,
        "Failed": 1,
        "Unknown": 0
      },
      "Mobile": {
        "Sent": 2,
        "Delivered": 2,
        "Failed": 0,
        "Unknown": 0
      },
      "Pager": {
        "Sent": 4,
        "Delivered": 0,
        "Failed": 0,
        "Unknown": 4
      }
    },
    {
      "Name": "Norway",
      "CountryCode": "+47",
      "Sent": 10,
      "Delivered": 10,
      "Failed": 0,
      "Unknown": 0
      "Mobile": {
        "Sent": 10,
        "Delivered": 10,
        "Failed": 0,
        "Unknown": 0
      }
    }
    ...
  ]
}

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

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 time zone is given CET/CEST is assumed (local time zone in Sweden).

HTTP Response

200 OK

A successful response contains a summary a long with a separation based on country and number type. Please note that a long message will be split up into several SMS. This statistic is based on the number of SMS rather than the number of messages sent.

429 Too Many Requests

Clients are allowed to fetch statistics once every 30 seconds. If multiple requests are made within this timeframe, the API will respond with the HTTP status code 429 Too Many Requests.

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 SMS in transit or where delivery report is not available.
Countries List List of Country objects. Only countries with at least one SMS sent will be included.

Country Object

Note: This object may contain several number types.

Key Type Description
Name String The name of the country, for descriptive purpose.
CountryCode String The call code with leading + sign.
Sent Integer Number of sent SMS.
Delivered Integer Number of delivered SMS.
Failed Integer Number of failed, not delivered SMS.
Unknown Integer Number of SMS in transit or where delivery report is not available.
Number Type Stat Object Present if there is at least one SMS sent to a number of this type. E.g. Mobile or Pager.

Number Type

This classification is done according to the number plan in each country.

Key Description
Mobile Mobile phone numbers.
FixedLine Fixed line phone numbers.
Pager Primarily Minicall in Sweden.
Other E.g. Voip and Voicemail.

Stat object

Key Type Description
Sent Integer Number of sent SMS.
Delivered Integer Number of delivered SMS.
Failed Integer Number of failed, not delivered SMS.
Unknown Integer Number of SMS in transit or where delivery report is not available.

Voice

With the voice APIs you can configure different call flows that can be used both for making and receiving calls. A flow may contain both dynamic contents, created by our text-to-speech (TTS) engine, or pre-recorded audio. Using DTMF tones, the flow may branch off, allowing different options during the call. Flow nodes may send messages containing various data, configuring those messages to be sent an SMS inbox with a NotificationURL configured you'll be able to integrate this voice channel with your own API.

Voice API structure

Path Description
/voice/flow The configured flows you may use to send voice messages or configure inbox messages.
/voice/message Create a voice call to deliver the message using a defined flow.
/voice/inbox List of configured inbound phone numbers configured on your account.
/voice/inbox/{VoiceInboxId} Actions on a specific inbox, e.g. add new messages.

The flow

List available flows

curl "https://api.genericmobile.se/SmsGateway/api/v1/voice/flow" \
  --basic -u Alice:secretPwd
200 OK
[
  {
    "FlowId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
    "Description": "Reads the text and asks the caller to press 1 or 2."
  },
  {
    "FlowId": "deadc0de-2bad-c4fe-feed-beefca1ff000",
    "Description": "Plays a pre-recorded message explaining who called and why."
  }
]

A voice flow is a graph over the call or parts of a call. They are rather flexible but at the cost of complexity. At the moment those flows are configured by Generic in collaboration with you. Common building blocks in the flow allows audio files to be played, synthesized text (TTS), DTMF detection with flow branching, sending SMS and more. It is also possible to define where in the flow you need to reach in order to call it delivered.
You may list the flows configured for you with a description to see what you have at your disposal when sending a voice message or configuring a voice inbox.

Example flow: When the flow starts, a prerecorded audio file is played saying "Hello". Then the text message is transformed into voice and played. In this example the text might have been "Press 1...the story ends, you wake up in your bed and believe whatever you want to believe. You press 2...you stay in Wonderland.". If not 1 nor 2 is pressed in a specified time, the message will be repeated once. If 1 or 2 is pressed you end up in the corresponding node that might have a prerecorded audio file attached regarding "deep rabbit holes". Either way, those two nodes will send a message to a pre-configured number/inbox (API) including who made the choice (phone number) and the reference of the message. The call will end with a nice "Goodbye" if 1 or 2 was presses within due time, or a short notice that no action was taken.

GET /voice/flow
HTTP Response

200 OK

A successful request contains a list of flow objects.

Flow object

Key Description Type
FlowId The unique ID of the flow used in various places in the /voice API. Guid
Description Short description what the flow does. String

Voice call

Deliver message with a voice call

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/voice/message \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "From": "+46846500400",
        "To": ["+46701740605"],
        "Text": "This is an urgent message",
        "FlowId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
        "Reference": "ID1234"
      }'
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

Communicating a message could be done with more than just text. By using our voice message API, you can define what call flow we should use when making a phone call to someone.
It is a better user experience if the number we are calling from is a number that the person can call back on, in case he/she missed the call. One great option is to set up your own number and configure a voice inbox. To simplify retry logic, additional call attempts, in case message was not delivered, retry delay and number of attempts are configured on the flow rather than per message. The flow description will have a short summary for you.

POST /voice/message

Voice call parameters

Parameter Required Type Default Description
From No Phone number1 Hidden number Phone number or empty for hidden number.
To Yes Array (1..1000) of Strings - List of recipient phone numbers.
Text No String "" Text to be synthesized.
FlowId Yes Guid - The ID of the flow to use.
Reference No String (0..255) null Tag the message with a custom reference. Usable when dissecting the message log.
DeliveryReportUrl No String (9..255) null http(s) URL for receiving delivery reports, if null or omitted no delivery report will be sent.

1 A phone number should be given in international format (leading + sign). Leave empty to hide the number.

HTTP Response

201 Created

A successful request contains a list of MessageIds, one per receiver. Similar to how our SMS message endpoint would.

Note: You may poll for delivery reports just as you do with any other message in our platform.

Voice inbox

curl "https://api.genericmobile.se/SmsGateway/api/v1/voice/inbox" \
  --basic -u Alice:secretPwd
200 OK
[
  {
    "VoiceInboxId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
    "PhoneNumber": "+46701740605",
  }
]

You would need to have a phone number configured for incoming calls. This is something Generic will help you set up. Once in place you may, just like on a regular voice mail, leave messages for whom ever calls this number. However, our voice inbox is a little bit smarter and allow you to have different messages depending on who is calling.
By using your inbox number as caller when sending voice messages, you may allow the recipient to call back at a more convenient time and get your message that way instead.
Internally, inboxes are based on four flows describing the inbox graph as show in the Inbox flow structure diagram. This structure is configured by Generic in collaboration with you.

Inbox flow structure: Describes how the different flows in the inbox object are connected. The quotes are for illustration purpose only.

GET /voice/inbox

HTTP Response

200 OK

A successful request contains a list of index object.

Inbox object

Parameter Type Description
VoiceInboxId Guid The ID used to reference this inbox.
PhoneNumber String Phone number configured to receive calls.

Inbox messages

You may put multiple messages in your voice inbox. Those messages could use different call flows and have different receivers depending on what number is calling your inbox. This way, you can communicate a single number but tailer the experience depending on who calls it.

Create inbox message

Create inbox message

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/voice/inbox/deadc0de-2bad-c4fe-feed-beefca1ff00d \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '{
        "MsgFlowId": "deadc0de-2bad-c4fe-feed-beefca1ff00d",
        "MsgText": "Det e fredag mina bekanta",
        "Receivers": ["+46701740605"]
      }'
201 Created
{
  "MessageId": ["deadc0de-2bad-c4fe-feed-beefca1ff00d"]
}

POST /voice/inbox/{VoiceInboxId}

Parameter Required Type Default Description
MsgFlowId Yes Guid - The flow ID to use for this messages.
MsgText No String "" If the MsgFlowId contains a TTS state, this text will be used.
Reference No String "" A custom reference that will be present in reports for convenient mapping.
Receivers No Array of Strings [] The strings should all be valid phone numbers.

HTTP Response

201 Created

A successful request contains the index message object.

400 Bad Request

List your voice inbox messages

GET /voice/inbox/{VoiceInboxId}

HTTP Response

200 OK

A successful request contains a list of index message objects.

Index message object

Parameter Type Description
VoiceInboxMessageId Guid The ID used to reference this inbox.
VoiceInboxId Guid The ID of the voice inbox this message should be put in.
MsgFlowId Guid The flow ID to use for this message.
MsgText String If the MsgFlowId contains a TTS state, this text will be used.
Reference String A custom reference that will be present in reports for convenient mapping.
Receivers Array of Strings The strings should all be valid phone numbers.

Remove a message from the voice inbox

DELETE /voice/inbox/{VoiceInboxId}/{VoiceInboxMessageId}

HTTP Response

204 No Content

Add receiver to inbox message

Add new receiver to a message

curl -X POST https://api.genericmobile.se/SmsGateway/api/v1/voice/inbox/deadc0de-2bad-c4fe-feed-beefca1ff00d/deadc0de-2bad-c4fe-feed-beefca1ff00d/receivers \
  --basic -u Alice:secretPwd \
  -H 'Content-Type: application/json' \
  -d '"+46701740605"'
200 OK
{
}

After a inbox message is created you may add more receivers.

POST /voice/inbox/{VoiceInboxId}/{VoiceInboxMessageId}/receivers

Pass thephone number to add as a single string in the body.

HTTP Response

200 OK

Empty response. Even if the receiver was present already. No duplicates will be stored.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Message": "The format of the phone number is wrong."}

Remove receiver from inbox message

curl -X DELETE https://api.genericmobile.se/SmsGateway/api/v1/voice/inbox/deadc0de-2bad-c4fe-feed-beefca1ff00d/deadc0de-2bad-c4fe-feed-beefca1ff00d/receivers/46701740605 \
  --basic -u Alice:secretPwd
204 No Content

After a inbox message is created you may remove specific receivers. The phone number to be removed should be in the path with the leading plus sign striped out. See the example.

DELETE /voice/inbox/{VoiceInboxId}/{VoiceInboxMessageId}/receivers/{PhoneNumber}

HTTP Response

204 No Content

Empty response.

400 Bad Request

Will contain a message explaining the issue, e.g. {"Message": "The format of the phone number is wrong."}

404 Not Found

If the receiver was not a receiver of the message.

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.

Delivery Report Errors

Error Code Reason
0 Success
1 Absent subscriber.
7 Validity expired
49 Temporary unknown error
51 Destination number is unknown
52 Invalid destination number
57 Message rejected because the destination number was blacklisted.
58 Country Information and local regulations, call Support
59 Invalid Source address
99 Permanent unknown error
101 Active disconnect / Delivery rule not fulfilled
151 Destination number is unknown
152 Invalid destination number

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. +46701740605. If part of an URI the + shall be omitted, e.g. 46701740605.