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:

  1. Authenticate with your Campaign Manager credentials.
  2. Decide whether to send with members included in the campaign request or upload a reusable list first.
  3. Create and schedule the campaign.
  4. Personalise content where needed using member parameters.
  5. 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:

  1. You have Campaign Manager API credentials and permission to access the API.
  2. You know the {application_name} value your requests should target.
  3. Mobile numbers are formatted in international format, for example +61421234567.
  4. Scheduled send times are provided as RFC3339 timestamps.
  5. Your campaign request includes either content or template.

First successful request path

For most implementations, the fastest way to validate connectivity and configuration is:

  1. Authenticate using your Campaign Manager credentials.
  2. Submit a simple scheduled campaign with direct members in the request body.
  3. Confirm the 201 Created response and store the campaign location or ID returned by the API.
  4. 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:

  1. Mobile number format must be in international format eg: +61421234567.
  2. A maximum of 1 million members is currently supported.
  3. 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
email Send replies to this email address string email 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)
end
import 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)
end
import 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
email Send replies to this email address string email 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.