Campaign Manager
When to choose Campaign Manager API
Choose Campaign Manager API when you want to create, personalise, schedule, and track outbound SMS campaigns from your own systems instead of managing campaign setup, recipient loading, templates, and reporting manually.
Overview
The Campaign Manager REST API is designed for teams that want to create, personalise, schedule, and track outbound SMS campaigns from their own systems. It gives your application direct control over campaign setup, recipient loading, template access, and campaign reporting using JSON over HTTPS.
For a technical buyer or implementation team, the key value is straightforward: this API helps you move bulk and personalised SMS sending out of manual workflows and into your own applications, platforms, and operational processes.
What the API can do
- Create scheduled SMS campaigns programmatically
- Send the same content to a full audience, or personalise content per recipient using parameters
- Load and manage recipient lists directly from your systems
- Access campaign reporting to understand message outcomes
- Retrieve templates already associated with your campaign application
How it works
In practice, the API follows a simple workflow:
- Authenticate with your Campaign Manager credentials.
- Decide whether to send with members included in the campaign request or upload a reusable list first.
- Create and schedule the campaign.
- Personalise content where needed using member parameters.
- Retrieve reports to review message status and campaign outcomes.
When to use Campaign Manager API
This API is a strong fit when you need to run bulk SMS or personalised bulk SMS from an existing system, rather than sending messages manually through an interface. It is especially useful when campaign creation needs to be automated, integrated into business workflows, or connected to customer data already held in your own platform.
If your evaluation criteria include scale, operational control, straightforward integration, and the ability to get time-sensitive messages into handsets quickly, Campaign Manager is the higher-level campaign orchestration layer that sits above raw transport detail and focuses on campaign execution.
Before you start
Before making your first request, confirm the following:
- You have Campaign Manager API credentials and permission to access the API.
- You know the
{application_name}value your requests should target. - Mobile numbers are formatted in international format, for example
+61421234567. - Scheduled send times are provided as RFC3339 timestamps.
- Your campaign request includes either
contentortemplate.
First successful request path
For most implementations, the fastest way to validate connectivity and configuration is:
- Authenticate using your Campaign Manager credentials.
- Submit a simple scheduled campaign with direct
membersin the request body. - Confirm the
201 Createdresponse and store the campaign location or ID returned by the API. - Retrieve the campaign report once messages have been processed.
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 Campaign Manager API credentials are the same as used to login. Navigate to the Campaign Manager application under ‘Send Messages’, and view the ‘API Info’ tab to obtain your API details.
If you don’t have these details, please contact support@modicagroup.com .
Base URI
All API access is over HTTPS, and accessed from:
https://api.modicagroup.com/rest/campaign_manager/v1
Versions
The Campaign Manager API version is currently v1.
OpenAPI Specification
This API has been developed in accordance with the OpenAPI specification defined here.
The OpenAPI (Swagger) specification can be found here: https://api.modicagroup.com/rest/campaign_manager/v1/swagger.json.
You can see code examples and further information here.
Limits and Defaults
The following limits and defaults apply for all resources:
- Mobile number format must be in international format eg:
+61421234567. - A maximum of 1 million members is currently supported.
- Time of Day Restrictions can be used to limit when campaigns may send, and will apply to all campaigns sent via API. The Sending Hours User Guide details how to setup Time of Day Restrictions.
Campaigns
Campaign creation is the core workflow for teams that want to trigger outbound SMS directly from their own systems. You can schedule a campaign with fixed message content for every recipient, or inject personalised values into the content for each member in the send.
If your application uses centrally managed message content, review the Templates section before scheduling campaigns so you know when to send with template rather than content.
Scheduling a Campaign
To schedule a campaign, send a POST to the following URI:
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/scheduled_campaigns
On success:
HTTP/1.1 201 Created
Location: https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/scheduled_campaigns/{campaign_id}
NOTE: Scheduling a campaign to an existing list is not supported.
Submit a POST request using the following attributes to schedule a campaign:
| FIELD | DESCRIPTION | TYPE | SUB TYPE | REQUIRED |
|---|---|---|---|---|
| name | Name of the List | string | yes | |
| schedule | Scheduled start time of the campaign | string | RFC3339 timestamp | yes |
| content | Content of the text message (only required if template is not set) | string | no | |
| template | Template id to invoke a template. Uses the template text as the content of the message (only required if content is not set) | string | no | |
| mask | Source Mask | string | no | |
| batch | Free text reference | string | no | |
| Send replies to this email address | string | no | ||
| reply_response | Automatic reply sent when a text is received | string | no | |
| opt_out_response | Automatic reply sent when an Opt-Out text is received | string | no | |
| members | List of members (destinations) to send the content to | list | member | yes |
| remove_opt_outs | Remove Opt-Outs from previous campaigns - Defaults to True | boolean | no | |
| strict_validation | If the set this flag to false, any invalid lines in the request will be ignored and the campaign will be scheduled. If there are ignored lines the response will report back on the mobile numbers ignored. e.g. {"error_messages":"Failed validation for +235456456445445, ignored." Failed validation for +11, ignored. ","id":126002} If set to true the request will not be scheduled. True is the default if this field is not included. |
boolean | no |
Static Campaign Example
curl -X POST "https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns" \
-u "username:password" \
-H "Content-Type: application/json" \
-d '{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there!",
"members": [
{ "destination": "+614123123123" },
{ "destination": "+614123123122" },
{ "destination": "+614123123121" },
{ "destination": "+614123123120" }
]
}'
await fetch("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns", {
method: "POST",
headers: {
"Authorization": "Basic " + btoa("username:password"),
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Campaign Name",
schedule: "2023-07-20T09:00:00+12:00",
content: "Hi there!",
members: [
{ destination: "+614123123123" },
{ destination: "+614123123122" },
{ destination: "+614123123121" },
{ destination: "+614123123120" }
]
})
});import requests
from requests.auth import HTTPBasicAuth
response = requests.post(
"https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns",
auth=HTTPBasicAuth("username", "password"),
json={
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there!",
"members": [
{"destination": "+614123123123"},
{"destination": "+614123123122"},
{"destination": "+614123123121"},
{"destination": "+614123123120"},
],
},
)<?php
$payload = [
"name" => "Campaign Name",
"schedule" => "2023-07-20T09:00:00+12:00",
"content" => "Hi there!",
"members" => [
["destination" => "+614123123123"],
["destination" => "+614123123122"],
["destination" => "+614123123121"],
["destination" => "+614123123120"],
],
];
$ch = curl_init("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns");
curl_setopt($ch, CURLOPT_USERPWD, "username:password");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);require "net/http"
require "uri"
require "json"
uri = URI("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns")
request = Net::HTTP::Post.new(uri)
request.basic_auth("username", "password")
request["Content-Type"] = "application/json"
request.body = {
name: "Campaign Name",
schedule: "2023-07-20T09:00:00+12:00",
content: "Hi there!",
members: [
{ destination: "+614123123123" },
{ destination: "+614123123122" },
{ destination: "+614123123121" },
{ destination: "+614123123120" }
]
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endimport java.nio.charset.StandardCharsets;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns"))
.header(
"Authorization",
"Basic " + Base64.getEncoder().encodeToString(
"username:password".getBytes(StandardCharsets.UTF_8)
)
)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("""
{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there!",
"members": [
{ "destination": "+614123123123" },
{ "destination": "+614123123122" },
{ "destination": "+614123123121" },
{ "destination": "+614123123120" }
]
}
"""))
.build();using System.Net.Http.Headers;
using System.Text;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password"))
);
var content = new StringContent("""
{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there!",
"members": [
{ "destination": "+614123123123" },
{ "destination": "+614123123122" },
{ "destination": "+614123123121" },
{ "destination": "+614123123120" }
]
}
""", Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns",
content
);This will schedule and send the verbatim content to all members in the members list. To insert variable content (using parameters), see below.
Customise content using parameters
To customise content per recipient, the ‘members’ field will need to contain the parameters you wish to substitute in the content:
| FIELD | DESCRIPTION | TYPE | REQUIRED |
|---|---|---|---|
| destination | The mobile number to send the content to | string | yes |
| param1 | Substitution parameter to include within the content | string | no |
| param2 | Substitution parameter to include within the content | string | no |
| param3 | Substitution parameter to include within the content | string | no |
| param4 | Substitution parameter to include within the content | string | no |
| param5 | Substitution parameter to include within the content | string | no |
| param6 | Substitution parameter to include within the content | string | no |
Dynamic Campaign Example
curl -X POST "https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns" \
-u "username:password" \
-H "Content-Type: application/json" \
-d '{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there %%1%%!",
"members": [
{ "destination": "+614123123123", "param1": "Bob" },
{ "destination": "+614123123122", "param1": "Sarah" },
{ "destination": "+614123123121", "param1": "Tyler" },
{ "destination": "+614123123120", "param1": "Paul" }
]
}'
await fetch("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns", {
method: "POST",
headers: {
"Authorization": "Basic " + btoa("username:password"),
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Campaign Name",
schedule: "2023-07-20T09:00:00+12:00",
content: "Hi there %%1%%!",
members: [
{ destination: "+614123123123", param1: "Bob" },
{ destination: "+614123123122", param1: "Sarah" },
{ destination: "+614123123121", param1: "Tyler" },
{ destination: "+614123123120", param1: "Paul" }
]
})
});import requests
from requests.auth import HTTPBasicAuth
response = requests.post(
"https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns",
auth=HTTPBasicAuth("username", "password"),
json={
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there %%1%%!",
"members": [
{"destination": "+614123123123", "param1": "Bob"},
{"destination": "+614123123122", "param1": "Sarah"},
{"destination": "+614123123121", "param1": "Tyler"},
{"destination": "+614123123120", "param1": "Paul"},
],
},
)<?php
$payload = [
"name" => "Campaign Name",
"schedule" => "2023-07-20T09:00:00+12:00",
"content" => "Hi there %%1%%!",
"members" => [
["destination" => "+614123123123", "param1" => "Bob"],
["destination" => "+614123123122", "param1" => "Sarah"],
["destination" => "+614123123121", "param1" => "Tyler"],
["destination" => "+614123123120", "param1" => "Paul"],
],
];
$ch = curl_init("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns");
curl_setopt($ch, CURLOPT_USERPWD, "username:password");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);require "net/http"
require "uri"
require "json"
uri = URI("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns")
request = Net::HTTP::Post.new(uri)
request.basic_auth("username", "password")
request["Content-Type"] = "application/json"
request.body = {
name: "Campaign Name",
schedule: "2023-07-20T09:00:00+12:00",
content: "Hi there %%1%%!",
members: [
{ destination: "+614123123123", param1: "Bob" },
{ destination: "+614123123122", param1: "Sarah" },
{ destination: "+614123123121", param1: "Tyler" },
{ destination: "+614123123120", param1: "Paul" }
]
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endimport java.nio.charset.StandardCharsets;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns"))
.header(
"Authorization",
"Basic " + Base64.getEncoder().encodeToString(
"username:password".getBytes(StandardCharsets.UTF_8)
)
)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("""
{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there %%1%%!",
"members": [
{ "destination": "+614123123123", "param1": "Bob" },
{ "destination": "+614123123122", "param1": "Sarah" },
{ "destination": "+614123123121", "param1": "Tyler" },
{ "destination": "+614123123120", "param1": "Paul" }
]
}
"""))
.build();using System.Net.Http.Headers;
using System.Text;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password"))
);
var content = new StringContent("""
{
"name": "Campaign Name",
"schedule": "2023-07-20T09:00:00+12:00",
"content": "Hi there %%1%%!",
"members": [
{ "destination": "+614123123123", "param1": "Bob" },
{ "destination": "+614123123122", "param1": "Sarah" },
{ "destination": "+614123123121", "param1": "Tyler" },
{ "destination": "+614123123120", "param1": "Paul" }
]
}
""", Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://{apiDomainName}/rest/campaign_manager/v1/{application_name}/scheduled_campaigns",
content
);This will schedule and send the variable content (including parameter 1 in this example) personalised to all recipients in the members list containing that parameter.
Campaign Error Codes
The following errors can occur:
Code |
Description |
|---|---|
| 401 - Unauthorised | Incorrect username and/or password |
| 403 - Forbidden | Not allowed access to the application, or, not allowed access to campaign manager |
| 404 - Not Found | URL is incorrect |
| 422 - Unprocessable Entity | Validation errors within the data |
| 4xx - | Something else is wrong with the request |
| 5xx - | Something is wrong with the service |
Sample error:
{
"code" : 401,
"message" : "unauthenticated for invalid credentials"
}
Lists
List management is useful when your application needs to prepare recipient data before campaign creation, reuse audience sets, or cleanly manage recipients outside the campaign request itself. The API supports creating lists, loading members with optional parameters, deleting lists, and retrieving lists already associated with your campaign application.
Uploading a List
To create a list perform a POST to the following URI:
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/lists
On success:
HTTP/1.1 201 List Created
Location: https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/lists/{list_id}
Note: The List ID that is returned should be stored in your database in order to delete a list in the future.
Submit a POST request using the following attributes to load a list:
| FIELD | DESCRIPTION | TYPE | SUB TYPE | REQUIRED |
|---|---|---|---|---|
| name | Name of the List | string | Yes | |
| batch | Free text reference | string | No | |
| Send replies to this email address | string | No | ||
| members | List of members (destinations) to send the content to | list | member | Yes |
| remove_opt_outs | Remove Opt-Outs from previous campaigns - Defaults to True | boolean | No | |
| strict_validation | If the set this flag to false, any invalid lines in the request will be ignored and the list will be loaded. If there are ignored lines the response will report back on the mobile numbers ignored. e.g. {“error_messages”:“Failed validation for +235456456445445, ignored. Failed validation for +11, ignored. “,“id”:126002} If set to true the request will not be loaded. True is the default if this field is not included. | boolean | No |
List creation example
{
"name" : "List Name",
"members" : [
{ "destination" : "+614123123123" },
{ "destination" : "+614123123122" },
{ "destination" : "+614123123121" },
{ "destination" : "+614123123120" }
]
}
List creation with parameters
To generate a POST request including parameters, the ‘members’ field will need to contain the parameters you want in the content:
| FIELD | DESCRIPTION | TYPE | REQUIRED |
|---|---|---|---|
| destination | The mobile number to send the content to | string | yes |
| param1 | Substitution parameter to include within the content | string | no |
| param2 | Substitution parameter to include within the content | string | no |
| param3 | Substitution parameter to include within the content | string | no |
| param4 | Substitution parameter to include within the content | string | no |
| param5 | Substitution parameter to include within the content | string | no |
| param6 | Substitution parameter to include within the content | string | no |
List creation with parameters
{
"name" : "List Name",
"members" : [
{ "destination" : "+614123123123", "param1" : "Bob" },
{ "destination" : "+614123123122", "param1" : "Sarah" },
{ "destination" : "+614123123121", "param1" : "Tyler" },
{ "destination" : "+614123123120", "param1" : "Paul" }
]
}
DELETE a List
Submit a HTTP DELETE request using the following form to delete a list:
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/lists/{list_id}
On success:
HTTP/1.1 204 List Deleted
Deleting Multiple Lists
Submit a HTTP POST request using the following form to delete multiple lists:
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/delete_multiple_lists
Use the following attribute in the request body:
| FIELD | DESCRIPTION | TYPE | SUB TYPE | REQUIRED |
|---|---|---|---|---|
| list_ids | List of IDs to be deleted | array | integer | Yes |
Deleting multiple lists example
{
"list_ids" : [
1234, 3456, 5678
]
}
On success, the following response is returned:
HTTP/1.1 200
{"list_ids":[1234, 3456, 5678],"message":"Deleted list ids"}
Note: if not all lists can be deleted, the request is still considered successful, and the response will only include the deleted list IDs.
GET all Lists
Submit a HTTP GET request using the following form to get all lists associated to a campaign application.
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/lists
On success:
HTTP/1.1 200 OK
[
{
"created":"2019-10-04T10:12:19.011Z",
"id":123456,
"name":"string",
"members":[
{
"destination":"+123456789",
"param1":"string",
"param2":"string",
"param3":"string",
"param4":"string",
"param5":"string",
"param6":"string"
},
{
"destination":"+123456789",
"param1":"string",
"param2":"string",
"param3":"string",
"param4":"string",
"param5":"string",
"param6":"string"
}
]
}
]
List Error Codes
The following errors can occur:
| Code | Description |
|---|---|
| 401 - Unauthorised | Incorrect username and/or password |
| 403 - Forbidden | Not allowed access to the application, or, not allowed access to campaign manager |
| 404 - Not Found | URL is wrong or List has already been deleted |
| 422 - Unprocessable Entity | Validation errors within the data |
| 4xx - | Something else is wrong with the request |
| 5xx - | Something is wrong with the service |
Sample error:
{
"code" : 401,
"message" : "unauthenticated for invalid credentials"
}
To generate your own client libs, click here.
Reports
Reporting comes after campaign execution, and is where delivery visibility becomes practical for engineering and operations teams. Once a campaign has been sent, the report endpoint lets you retrieve message-level outcomes so you can reconcile sends, track statuses, and feed downstream reporting or internal dashboards.
GET a report summary
Issue an HTTP GET request to the following URL to access a report for a given campaign:
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/{campaign_id}/report
On success:
HTTP/1.1 200 OK
[
{
"list_name":"string",
"message_id":123456789,
"mobile":"+64123456",
"sent_date":"2019-02-19 15:48:01.894677",
"status":"received",
"status_date":"2019-02-19 15:48:03.498389",
"timezone":"Pacific/Auckland"
},
{
"list_name":"string",
"message_id":123456789,
"mobile":"+6412345678",
"sent_date":"2019-02-19 15:48:01.744065",
"status":"failed",
"status_date":"2019-02-19 15:48:03.192748",
"timezone":"Pacific/Auckland"
}
]
Report Error Codes
The following errors can occur:
| Code | Description |
|---|---|
| 401 - Unauthorised | Incorrect username and/or password |
| 403 - Forbidden | Not allowed access to the application, or, not allowed access to campaign manager |
| 404 - Not Found | URL is wrong |
| 422 - Unprocessable Entity | Validation errors within the data |
| 4xx - | Something else is wrong with the request |
| 5xx - | Something is wrong with the service |
Sample error:
{
"code" : 401,
"message" : "unauthenticated for invalid credentials"
}
To generate your own client libs, click here.
Templates
Templates are useful when campaign content is governed centrally and selected at send time rather than assembled in every request. This endpoint lets your application retrieve the templates already available to the campaign application so they can be referenced in campaign creation.
GET all Templates
Submit a HTTP GET request to the following URL get all templates associated to a campaign application.
https://api.modicagroup.com/rest/campaign_manager/v1/{application_name}/templates
On success:
HTTP/1.1 200 OK
[
{
"id":123,
"name":"template_name"
}
]
Template Error Codes
The following errors can occur:
| Code | Description |
|---|---|
| 401 - Unauthorised | Incorrect username and/or password |
| 403 - Forbidden | Not allowed access to the application, or, not allowed access to campaign manager |
| 404 - Not Found | URL is wrong |
| 422 - Unprocessable Entity | Validation errors within the data |
| 4xx - | Something else is wrong with the request |
| 5xx - | Something is wrong with the service |
Sample error:
{
"code" : 401,
"message" : "unauthenticated for invalid credentials"
}
To generate your own client libs, click here.