REST v1
When to choose REST v1
Choose REST v1 when you are maintaining or extending an existing Mobile Gateway integration that already uses v1 endpoints, callbacks, or response formats, because it preserves compatibility and avoids unnecessary migration work; new integrations should evaluate REST v2 first.
Overview
Modica’s Mobile Gateway REST API allows you to schedule and/ or immediately send messages to a single handset, or broadcast to multiple handsets.
HTTPS use is mandatory, all attempts to use plain-text HTTP will be redirected to HTTPS. Request and response data requires JSON encoding. Only HTTP GET and POST methods are required.
What the API can do
- Send SMS messages to a single handset
- Broadcast the same SMS message to multiple handsets
- Schedule messages for future delivery
- Retrieve submitted message details
- Receive inbound MO message callbacks
- Receive delivery receipt callbacks for message status updates
How it works
In practice, the API follows a simple workflow:
- Authenticate with your Mobile Gateway REST API credentials.
- Submit a JSON request to send, broadcast, schedule, or retrieve a message.
- Store the message ID returned by the API.
- Use the message ID to retrieve message details or reconcile delivery receipt callbacks.
- Configure callback URLs when your application needs inbound message or delivery status events.
When to use REST API
Use REST API when your application needs direct SMS sending and message tracking over HTTPS. It is a good fit for transactional messages, operational alerts, scheduled sends, and system-to-system workflows where your application controls the message content and destination data.
If you need lower-level control over individual SMS submissions and delivery status handling, REST API gives you a direct integration point for sending messages and receiving message lifecycle events.
Before you start
Before making your first request, confirm the following:
- You have Mobile Gateway REST API credentials.
- Your server IP address is authorised if IP allowlisting is enabled.
- Mobile numbers are formatted in international format, for example
+64211234567. - Your requests use HTTPS and JSON encoding.
- Your requests include the correct REST v1
Acceptheader when you need to specify the API version.
First successful request path
For most implementations, the fastest way to validate connectivity and configuration is:
- Authenticate using your REST API credentials.
- Submit a simple POST request to
/messageswithdestinationandcontent. - Confirm the
201 Createdresponse and store the returned message ID. - Retrieve the message with
GET /messages/{message_id}.
Authentication
HTTP Basic Authentication is used for all requests. If you access the API without having the correct credentials OR permission to access the API, you will get a HTTP 401 response.
Your gateway application credentials (application name and password) are available on the REST API configuration page in iAds Biz.
You will need a user account and password to retrieve these.
If you don’t have these details, please contact support@modicagroup.com.
Authorised IP Addresses
You can whitelist your servers’ IPs or IP ranges using the ‘Add IP Address’ button under “Authorised IP Addresses”
Please note: once one or more IP addresses or IP ranges have been added *connections from all other IP addresses will be rejected, any attempt from an *IP not in the list will receive an Authentication error.
Base URI
All API access is over HTTPS, and accessed from:
https://api.modicagroup.com/rest/gateway
Versions
The REST API version is currently v1. A custom media type is used to let consumers choose the data format they wish to receive:
Accept: application/vnd.modica.gateway.v1+json
OpenAPI Specification
The OpenAPI (Swagger) specification can be found here: here.
You can see code examples and further information here.
Error Codes
The following errors can occur:
| Code | Description |
|---|---|
| send_failed | Could not queue message due to an unknown error |
| invalid_json | Invalid JSON data in the request body |
| missing_attrib | Missing a required attribute |
| invalid_attrib | Invalid attribute value |
| broadcast_limit | Broadcast limit has been exceeded, please consult the error description for more detail. |
| 400 | Invalid scheduled timestamp (must be RFC3339) |
| 422 | Invalid scheduled timestamp (must not be in the past) |
| 404 | 404 Not Found. The requested URL was not found on this server. URI is incorrect or Address is truncated, e.g. for POST; using incomplete address like https://api.modicagroup.com/rest/gateway instead of the correct full address; https://api.modicagroup.com/rest/gateway/messages |
Date Strings
Complete date plus hours, minutes, seconds & timezone: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
YYYY = four-digit year
MM = two-digit month (01=January, etc.)
DD = two-digit day of month (01 through 31)
hh = two digits of hour (00 through 23) (am/pm NOT allowed)
mm = two digits of minute (00 through 59)
ss = two digits of second (00 through 59)
s = one or more digits representing a decimal fraction of a second
TZD = time zone designator (Z or +hh:mm or -hh:mm)
Sending messages
It is possible to send to either a single destination, or to broadcast one set of content to multiple destinations:
Sending to a single destination
To send an (outbound) MT message to a single destination, submit a POST request:
POST /messages
{
"destination": str:mobile-number,
"content": str:text-message
}
Optional attributes:
{
"scheduled": str: 2017-05-05T10:00:00+12:00,
"source": str:short-code,
"reference": str:alt-reference,
"class": str:application-class,
"mask": str:source-mask,
"sms_class": int:0-3,
"expires": str: 2017-05-05T10:00:00+12:00
}
On success:
HTTP/1.1 201 Created
Location: https://api.modicagroup.com/rest/gateway/messages/int:message-id
[integer($int64):message-id]
On validation error:
HTTP/1.1 400 Bad Request
{
"error": str:error-code
"error-desc": [str:error-desc]
}
{
"error-desc": "Invalid scheduled timestamp (must be less than 60 days)",
"error": "invalid_attrib"
}
Send SMS Message Example
These examples send a single SMS message using the REST API.
curl -v \
-H 'Content-Type: application/json' \
-u '<USERNAME>:<PASSWORD>' \
-d '{"content": "Hello world!", "destination": "+64211234567"}' \
https://{apiDomainName}/rest/gateway/messages
const credentials = btoa("gw_username:abcde12345");
const response = await fetch("https://{apiDomainName}/rest/gateway/messages", {
method: "POST",
headers: {
"Accept": "application/json",
"Authorization": `Basic ${credentials}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
destination: "+64211234567",
content: "Hello world!"
})
});
const messageId = await response.json();import requests
import json
from base64 import b64encode
uri = 'https://{apiDomainName}/rest/gateway/messages'
username = "gw_username"
password = "abcde12345"
# Authorization token
def basic_auth(username, password):
token = b64encode(f"{username}:{password}".encode('utf-8')).decode("ascii")
return f'Basic {token}'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization' : basic_auth(username, password)
}
json_payload = json.dumps({
"destination": "+64211234567",
"content": "Hello world!"
})
response = requests.post(uri, headers=headers, data=json_payload)
if response.status_code == 201:
print(response.json())
else:
print("Error:", response.status_code, response.text)<?php
$uri = "https://{apiDomainName}/rest/gateway/messages";
$json_payload ='{"content": "Hello world!", "destination": "+64211234567"}';
$request = curl_init($uri);
curl_setopt($request, CURLOPT_POST, True);
curl_setopt($request, CURLOPT_USERPWD, "user:password");
curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($request, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
curl_setopt($request, CURLOPT_POSTFIELDS, $json_payload);
$response = curl_exec($request);
$http_status = curl_getinfo($request, CURLINFO_HTTP_CODE);
echo "HTTP ".$http_status."\n".$response."\n";
curl_close($request);
?>
require 'net/http'
uri = URI.parse('https://{apiDomainName}/rest/gateway/messages')
json_payload = '{"content": "Hello world!", "destination": "+64211234567"}'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request.basic_auth('username', 'password')
request.body = json_payload
response = http.request(request)
puts 'HTTP %s' % response.code
puts response.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
String token = Base64.getEncoder()
.encodeToString("gw_username:abcde12345".getBytes(StandardCharsets.UTF_8));
String payload = """
{
"destination": "+64211234567",
"content": "Hello world!"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/gateway/messages"))
.header("Accept", "application/json")
.header("Authorization", "Basic " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes("gw_username:abcde12345"));
var request = new HttpRequestMessage(
HttpMethod.Post,
"https://{apiDomainName}/rest/gateway/messages");
request.Headers.Accept.ParseAdd("application/json");
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
request.Content = new StringContent(
"""{"destination":"+64211234567","content":"Hello world!"}""",
Encoding.UTF8,
"application/json");
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();use strict;
use warnings;
use JSON;
use LWP::UserAgent;
#
# Alter these to your supplied credentials
#
my $username = 'username';
my $password = 'password';
my $message = { content => 'Hello world!',
destination => '+64211234567' };
my $json_payload = to_json($message);
my $URI = 'https://{apiDomainName}/rest/gateway/messages';
my $request = HTTP::Request->new('POST', $URI);
$request->authorization_basic($username, $password);
$request->content($json_payload);
my $ua = LWP::UserAgent->new();
my $response = $ua->request($request);
printf("HTTP %s\n", $response->code);
print $response->content . "\n";Output:
HTTP 201
[message_id]
Broadcasting to multiple destinations
To broadcast a common message to a multiple devices, submit the following POST request:
POST /messages/broadcast
{
"destination": [str:mobile-number-1, str:mobile-number-2],
"content": str:text-message
}
Optional attributes:
{
"scheduled": str: 2017-05-05T10:00:00+12:00,
"source": str:short-code,
"reference": str:alt-reference,
"class": str:application-class,
"mask": str:source-mask,
"sms_class": int:0-3,
"expires": str: 2017-05-05T10:00:00+12:00
}
On success:
HTTP/1.1 201 Created
Content-Type: application/json
[
{
"status": "success",
"message": null,
"destination": str:mobile-number,
"id": integer($int64):message-id
}
]
On validation error:
HTTP/1.1 400 Bad Request
{
"error": str:error-code
"error-desc": [str:error-desc]
}
Example showing a mixed response of successful and failed destinations:
HTTP/1.1 201 Created
Content-Type: application/json
[
{
"status": "success",
"message": null,
"destination": str:mobile-number,
"id": integer($int64):message-id
},
{
"status": "failure",
"message": "Invalid destination (X)",
"destination": "X",
"id": null
},
{
"status": "failure",
"message": str:failure-reason,
"destination": str:mobile-number,
"id": null
}
]
Retrieving an SMS Message
To retrieve a message submit a GET request:
GET /messages/id
If a match is found:
HTTP/1.1 200 OK
Location: https://api.modicagroup.com/rest/gateway/messages/int:message-id
{
"id": str:message-id,
"source": str:mobile-number|short-code,
"destination": str:mobile-number|short-code,
"content": str:text-message
}
Additional attributes are added if available:
{
"reference": str:alt-reference,
"reply_to": str:message-id,
"operator": str:operator-name
}
If not found:
HTTP/1.1 404 Not Found
Get SMS Message Example
These examples retrieve an SMS message using the REST API.
curl -v \
-u '<USERNAME>:<PASSWORD>' \
https://{apiDomainName}/rest/gateway/messages/message_id
const credentials = btoa("user:password");
const response = await fetch("https://{apiDomainName}/rest/gateway/messages/message_id", {
method: "GET",
headers: {
"Authorization": `Basic ${credentials}`
}
});
const message = await response.text();import requests
uri = 'https://{apiDomainName}/rest/gateway/messages/message_id'
response = requests.get(uri, auth=('user', 'password'))
print('HTTP %s' % response.status_code)
print(response.text)<?php
$uri = "https://{apiDomainName}/rest/gateway/messages/message_id";
$request = curl_init($uri);
curl_setopt($request, CURLOPT_USERPWD, "user:password");
curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($request);
$http_status = curl_getinfo($request, CURLINFO_HTTP_CODE);
echo "HTTP ".$http_status."\n".$response."\n";
curl_close($request);
?>
require 'net/http'
uri = URI.parse('https://{apiDomainName}/rest/gateway/messages/message_id')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
request.basic_auth('username', 'password')
response = http.request(request)
puts 'HTTP %s' % response.code
puts response.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
String token = Base64.getEncoder()
.encodeToString("user:password".getBytes(StandardCharsets.UTF_8));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/gateway/messages/message_id"))
.header("Authorization", "Basic " + token)
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes("user:password"));
var request = new HttpRequestMessage(
HttpMethod.Get,
"https://{apiDomainName}/rest/gateway/messages/message_id");
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();use LWP::UserAgent;
my $uri = 'https://{apiDomainName}/rest/gateway/messages/message_id';
my $request = HTTP::Request->new('GET', $uri);
$request->authorization_basic('username', 'password');
my $ua = LWP::UserAgent->new(ssl_opts => {verify_hostname => 0});
my $response = $ua->request($request);
printf("HTTP %s\n", $response->code);
print $response->content . "\n";Output:
HTTP 200
{
"id": message_id,
"content": "Hello world!",
"source": "+64211234567",
"destination": "+64211234567",
}
MO Callback
You will only receive MO messages if you have configured an MO callback URL within your API Configuration.
We recommend using https:// for your callback URLs.
When a MO message is received for you a POST request is made to the MO callback URL, this callback will include the MO message detail as a JSON object in the body of the POST request.
POST callback-url
Location: https://api.modicagroup.com/rest/gateway/messages/int:message-id
{
"id": int:message-id,
"source": str:mobile-number,
"destination": str:short-code,
"content": str:text-message,
"operator": str:operator-name
}
In the case that the message is a reply to an MT message an additional “reply_to” attribute is added (only when a number sequence is used, and the MO is in reply to an MT message):
{
"reply_to": str:message-id
}
If the message contains a reply_to and the MT message had a reference provided, then an additional parameter will be added:
{
"reference": str:reference
}
If the message from the handset contains binary content, one additional attribute will be supplied:
{
"encoding": str:encoding-type
}
The value “base64” will be supplied for messages containing binary data. Content will be supplied encoded using base64, decoding content is needed to obtain the original data. NOTE: Regular SMS messages with GSM 7-bit or Unicode content will not supply this parameter.
DLR Callback
You will only receive DLR Statuses if you have configured a DLR callback URL within your API Configuration.
We recommend using https:// for your callback URLs.
When a DLR message is received for you a POST request is made to the DLR callback URL, this callback will include the DLR Status detail as a JSON object in the body of the POST request.
POST callback-url
{
"message_id": str:message-id,
"status": str:dlr-status
}
In the case that the MT message contained a reference, an additional “reference” attribute is added:
{
"reference": str:alt-reference
}
DLR Message Status
The following are the status codes returned in DLRs that our message gateway supports.
| Status | Description |
|---|---|
| sent | Message has been sent by the carrier transport |
| received | Message has been received |
| rejected | The carrier rejected the message |
| expired | The carrier was unable to deliver the message in a specified amount of time. For instance when the phone was turned off. |
Omni Message Status
The following are the status codes viewable within Omni reports that our message gateway supports, not all carriers will support all of them.
| Status | Description |
|---|---|
| submitted | Message successfully submitted to the carrier for delivery |
| sent | Message has been sent by the carrier transport |
| received | Message has been received |
| frozen | A transient error has frozen this message |
| rejected | The carrier rejected the message |
| failed | Message delivery has failed due to carrier connectivity issue |
| dead | Message killed by administrator |
| expired | The carrier was unable to deliver the message in a specified amount of time. For instance when the phone was turned off. |
Help
Having trouble integrating with any of our services? Contact support@modicagroup.com and we’ll help you sort it out.