Interactive documentation · Developer portal · OpenAPI specification · EN · FR · DE · IT · PT · ES

Mailpro™ SMS API : Reference

Base URL : https://api.mailpro.com/sms

The Mailpro™ SMS API lets you programmatically manage phone contact lists, phone numbers, and send bulk or individual SMS messages.

Authentication

Every endpoint accepts three authentication methods. Use whichever fits your stack.

> Legacy Bearer JWT and id_client+api_key keep working unchanged and are > not scope-gated. Only OAuth 2.0 access tokens are subject to the > per-endpoint scope checks shown on each operation below.

Method 1 — OAuth 2.0 (recommended for integrations)

Mailpro runs one OAuth 2.0 authorization server for all of its APIs, at a single version-neutral surface: https://api.mailpro.com/oauth/. There is no per-version OAuth endpoint — you obtain a token from /oauth/token and the same token works on this SMS API, on CRM v3 and on Email v2. Which endpoints it may call is governed by the token's scopes, not the API base URL. Issuer (iss claim): https://api.mailpro.com/oauth/.

EndpointURL
AuthorizeGET https://api.mailpro.com/oauth/authorize
Token / RefreshPOST https://api.mailpro.com/oauth/token
JWKSGET https://api.mailpro.com/oauth/.well-known/jwks
DiscoveryGET https://api.mailpro.com/oauth/.well-known/openid-configuration

Grants: authorization_code + PKCE (S256, mandatory), client_credentials, refresh_token (rotation). Access-token TTL 20 min; refresh token 30 days (sliding, single-use); auth code 60 s.

Quickstart — get a token and call this API (replace placeholders; never commit a real secret):

curl -X POST https://api.mailpro.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=sms:send sms:read"

Then call this API with Authorization: Bearer ACCESS_TOKEN. The same token works on the CRM v3 and Email v2 APIs. A token missing an endpoint's required scope gets 403 insufficient_scope. Full flow walk-through and scope catalog: see the CRM v3 API docs › Authentication. SMS-relevant scopes: sms:send, sms:read, sms:contacts:read, sms:contacts:write, account:read.

Method 2 — Bearer JWT (legacy)

Authorization: Bearer <access_token>

Get a token via POST /token (form-encoded, OAuth2 password grant):

POST https://api.mailpro.com/sms/token
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=YOUR_USERNAME&password=YOUR_API_KEY

The same token is also valid on the CRM API v3 and the Email v2 API — authenticate once, call any API. Tokens are valid for 30 days by default; use grant_type=refresh_token to renew without re-authenticating. Not scoped — prefer OAuth 2.0 for installable integrations.

Method 3 — id_client + api_key

Two credentials:

ParameterTypeDescription
id_clientintegerYour numeric Mailpro client ID, found in Settings → API access
api_keystringYour API key (GUID format), found in Settings → API access

Send them in either of these places — pick one:

If you provide credentials in more than one place, the header wins.

OAuth scope enforcement per endpoint (SMS)

For OAuth-issued tokens, each endpoint group requires a scope (legacy auth is exempt). Each operation lists its scope under Authorization. Summary:

EndpointsRequired scope
/send/* (bulk, single, scheduling)sms:send
/history/list, /credit/getsms:read
/phone/list, /list/listsms:contacts:read
/phone/{add,edit,del}, /list/{edit,del}, /import/uploadsms:contacts:write
/account/limitsaccount:read

> POST /list/add (create a list) is currently reachable by any > valid token — it is not yet scope-gated. Scope rejection on the gated > endpoints returns 403 with > { "error": "insufficient_scope", "required_scope": "…" }.

Response format

All endpoints support json (default) and xml. Specify the format in the URL:

Field names in responses are PascalCase (TotalCredits, FirstName, …), while request parameters are snake_case (id_client, address_book_id, …). List endpoints wrap their rows in an Items array.

Pagination

Same rule on the three Mailpro APIs (Email v2, CRM v3, SMS): 5,000 items per page, by default and at most.

Unknown parameters are ignored, never rejected. When a request carries a parameter the API does not recognise, the response includes X-Ignored-Parameters (the names) and X-Documentation (a link to this page), so a typo does not go unnoticed.

SMS credit cost

One SMS costs country credits × number of parts.

Country credits — each destination country has a price of 1, 2 or 3 credits, based on the phone's international prefix. Sending to a number whose prefix we don't price is rejected with 400.

Number of parts — a message longer than one SMS is split by the operator and each part is charged. The limit depends on the characters used:

AlphabetSingle messagePer part when split
GSM-7 (standard latin)160 chars153 chars
Unicode (accented beyond GSM-7, Cyrillic, emoji, …)70 chars67 chars

A single character outside GSM-7 switches the whole message to Unicode, so one emoji can take a 160-character message from 1 part to 3. The characters ^ { } [ ] ~ | \ and € count as two each, even though they are GSM-7.

*Example:* a 300-character message in standard latin = 2 parts; sent to a 2-credit country, it costs 2 × 2 = 4 credits per recipient.

Phone number format

Phone numbers are normalized automatically. You can send them in many formats — spaces, dashes, dots, slashes, parentheses, underscores and non-breaking spaces are stripped before validation. Any other character (letters, apostrophes, =, ;, etc.) makes the number invalid.

ValidInvalid
+41794849980 — E.164 international0612345678 — national format (leading 0)
0041 79 484 99 80 — 00-prefix + spaces41'794'849'80 — apostrophes (not stripped)
+33 6-12-34-56-78 — + with dashestel=0041794849980 — extra characters
41794849980 — bare digits1234567 — too short (< 8 digits)

Rules:

Error codes

HTTPCodeMeaning
400103Malformed input — missing or invalid required parameter
202202Insufficient SMS credits
401Invalid id_client / api_key
500500Internal error

Webhooks

Mailpro™ can notify your server in real time when SMS events happen on your account (an SMS is delivered, an SMS fails, your credit balance is low, etc.). Stripe-style — your URL receives an HMAC-SHA256 signed POST as soon as the event fires.

Each event sent to your webhook counts as 1 request against your API request quota.

How it works

> ⏱ Activation delay — after you create, update or delete a webhook, the > change takes up to 10 minutes to propagate across the Mailpro API > servers. During that window events may not yet match your new subscription > (or may still match a just-removed one). This is the time required to > refresh the in-memory subscription cache on every API instance.

Payload envelope

All events share a common envelope:

{
  "id":         "evt_8f3a9b2c4d1e5f6789abcdef01234567",
  "type":       "sms.queued",
  "created":    1748194800,
  "apiVersion": "sms",
  "account":    { "id": 12345, "name": "ACME Corp" },
  "data":       {
    "messageId":   12345,
    "to":          "41791234567",
    "queuedAt":    "2026-05-27T14:32:12.0123456Z",
    "scheduledAt": "2026-05-27T14:32:12.0123456Z",
    "parts":       1
  }
}
FieldFormatDescription
idevt_ + 32 hexUnique event ID — use as an idempotency key on your side.
type<domain>.<verb>Canonical event type.
createdUnix seconds UTCIncluded in the HMAC signature.
apiVersion"sms" for events emitted by POST /sms/send/add_single; "v3" for events emitted by POST /v3/Sms/SingleSMS; "watcher" for DLR-driven events emitted by the worker.Which Mailpro component published the event.
account.idintYour Mailpro client ID (= id_client).
account.namestringYour account name (handy for client-side debug).
dataobjectEvent payload — shape depends on type (see catalog below).

Event catalog

Only the events listed below are actually emitted. The shapes are the literal JSON sent by the platform — match these field names exactly when parsing.

EventTriggerdata shape
pingTest via POST /webhooks/{id}/test{ message }
sms.queuedPOST /sms/send/add_single or POST /v3/Sms/SingleSMS accepted into the Mailpro send queue{ messageId: int, to: string, queuedAt: ISO-8601, scheduledAt: ISO-8601, parts: int }
sms.deliveredDLR with carrier code 004 or 008 (success codes){ messageId: int, phone: string, stateCode: string, dlrDate: datetime }
sms.failedDLR with any other carrier code (timeout, undelivered, rejected, blacklisted, …){ messageId: int, phone: string, stateCode: string, dlrDate: datetime }
credits.sms.lowSMS credit balance fell under your alert threshold (worker CreditsLowWatcher){ remaining: int, threshold: int, alertedAt: ISO-8601 }

> Note — there is no sms.sent event. The carrier DLR is the only feedback > the platform receives between "queued" and "delivered/failed", so the next > event you receive after sms.queued is either sms.delivered (success) or > sms.failed (error). Most messages reach the carrier within seconds and a > DLR within minutes; mobile-network conditions can occasionally extend this > to hours.

> Field naming — sms.queued uses to (the destination as submitted by > the API caller, after normalization). sms.delivered / sms.failed use > phone (the destination as returned by the carrier on the DLR). They will > be the same digits in practice, but the names differ because the events > originate from different code paths.

Subscribe to all events of this API by passing ["*"] in the events array.

HMAC signature

Every POST carries an X-Mailpro-Signature header:

X-Mailpro-Signature: t=1748194800,v1=7f9ac2b6e4d1c8a3...
X-Mailpro-Event-Id:  evt_8f3a9b2c4d1e5f6789abcdef01234567
X-Mailpro-Event-Type: sms.delivered
X-Mailpro-Attempt:   1

To verify:

Node.js
const crypto = require('crypto');

function verifyMailproSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
  if (Math.abs(Date.now() / 1000 - parseInt(parts.t)) > 300) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(parts.t + '.' + rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(parts.v1, 'hex'),
    Buffer.from(expected, 'hex'));
}
PHP
function verifyMailproSignature(string $rawBody, string $header, string $secret): bool {
    parse_str(str_replace(',', '&', $header), $p);
    if (abs(time() - (int)$p['t']) > 300) return false;
    $expected = hash_hmac('sha256', $p['t'] . '.' . $rawBody, $secret);
    return hash_equals($expected, $p['v1']);
}
Python
import hmac, hashlib, time

def verify_mailpro_signature(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split('=') for p in header.split(','))
    t = int(parts['t'])
    if abs(time.time() - t) > 300:
        return False
    expected = hmac.new(
        secret.encode(),
        f"{t}.".encode() + raw_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, parts['v1'])
C#
using System.Security.Cryptography;
using System.Text;

static bool VerifyMailproSignature(string rawBody, string header, string secret) {
    var parts = header.Split(',')
        .Select(p => p.Split('='))
        .ToDictionary(a => a[0], a => a[1]);
    var t = long.Parse(parts["t"]);
    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($"{t}.{rawBody}"));
    var expected = Convert.ToHexString(hash).ToLowerInvariant();
    return CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(expected),
        Encoding.UTF8.GetBytes(parts["v1"]));
}

Retry and auto-disable

AttemptDelay before next try
1 → 210 seconds
2 → 31 minute
3 → 45 minutes
4 → 530 minutes
5 → 62 hours
6 → 76 hours
7abandoned (delivery marked failed)

After 10 consecutive failures on the same webhook, it is automatically disabled (isActive: false) and you receive a notification email. Re-enable it with PUT /webhooks/{id} once your endpoint is fixed.

Success = HTTP 2xx

We treat your webhook as successful only if you return a status in 200–299. Any 3xx/4xx/5xx or a timeout (> 10 s) counts as a failure and triggers retries. If your endpoint is permanently dead, return 410 Gone explicitly — retries still happen but the failure reason is clearer in your delivery log.

Limits

LimitValue
Webhooks per account20
Subscribed events per webhook50
Max payload size256 KB
HTTP timeout per attempt10 seconds
Delivery history retention30 days

Contents

Authentication

Obtain a Bearer JWT token to authenticate all other API calls. The SMS /token endpoint is a 307 redirect to the canonical /v3/token issuer — your HTTP client follows the redirect transparently (POST method and body are preserved).

POST /token

Get access token (307 redirect to /v3/token)

Obtains a Bearer JWT token using Mailpro client credentials. Pass the returned access_token as Authorization: Bearer <token> in all subsequent requests. The same token is also valid on the CRM API v3 and the Email v2 API.

> ⚙ Implementation detail — POST /sms/token is a 307 Temporary > Redirect to POST /v3/token (configured at the IIS web.config > rewrite layer). HTTP 307 preserves both the method (POST) and > the request body, so any standards-compliant HTTP client follows > the redirect transparently — you keep posting to /sms/token and get > a valid JWT back. There is no duplicated token-issuance logic; the > SMS API never issues tokens itself.

Supported grant types
Grant typeUse case
passwordStandard integration — username + API key
refresh_tokenRenew an expiring access token without re-authenticating
client_credentialsServer-to-server with client ID only
Token lifetime

Use grant_type=refresh_token to renew the access token without re-authenticating. Store tokens server-side (Vault, env vars); never embed in browser JS or mobile app binaries. See the CRM API v3 /token doc for the full security note.

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
grant_typestring: password, refresh_token, client_credentialsyes
usernamestringYour Mailpro username (email). Required for password grant.
passwordstringYour Mailpro API key (GUID format). Required for password grant.
refresh_tokenstringPrevious refresh token. Required for refresh_token grant.
client_idstringYour Mailpro client ID (integer). Required for client_credentials grant.

Responses

CodeDescription
200Token issued successfully. Returned by POST /v3/token after the transparent 307 follow — your HTTP client sees a normal 200 with the same body shape it would receive directly from the v3 token endpoint.
307Temporary Redirect to POST /v3/token, issued by the IIS rewrite rule in web.config. Standards-compliant HTTP clients follow this automatically and preserve the original POST method + form body. Visible only to clients that explicitly disable redirect following (e.g. curl --max-redirs 0).
400Invalid credentials or unsupported grant type

Example 200

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 31535999,
  "userName": "12345",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "application": null
}

Example 400

{
  "error": "invalid_grant",
  "error_description": "The username or password is incorrect."
}

Account

Check your SMS credit balance, monthly API quota, and account status.

GET /account/limits.{format}

Get monthly API quota

Returns the monthly API request quota for the authenticated client.

Quota calculation: the limit is calibrated from the email subscription credits (typically subscription_credits × 5). For a 10,000-email/month plan, this yields a 50,000-request monthly budget. Reset on the subscription anniversary date (not the 1st of the calendar month).

What consumes credits:

What is FREE (does not consume credits):

The quota is shared across all 3 Mailpro APIs (v2, v3, sms) — one client = one monthly budget across the whole platform. SMS sends additionally consume the dedicated SMS credit balance (GET /credit/get.{format}).

OAuth scope : account:read

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Responses

CodeDescription
200Quota snapshot
401Invalid credentials
404No quota record found (newly created account; row will be created on the first authenticated request).

Example 200

{
  "monthlyLimit": 50000,
  "remaining": 32847,
  "used": 17153,
  "isFree": false,
  "remainedSendsForFree": null
}

Send SMS

Send SMS messages — either a single transactional SMS to one recipient, or a bulk campaign to an entire contact list.

POST /send/add.{format}

Send bulk SMS to a contact list

Sends an SMS message to all phone numbers in a contact list. Supports scheduling: set scheduled_time to a future date to send later, or omit it to send immediately.

Credit consumption: credits are deducted at send time. Long messages (>160 GSM-7 chars) are split into multiple parts, each costing additional credits.

The response returns { "Error": "Insufficient Credit", "Code": 202 } if the account has insufficient credits.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
messagestringyesSMS message text. Keep under 160 characters for a single-part SMS. Characters outside the GSM-7 alphabet (e.g. Chinese, Arabic, emoji) switch the encoding to Unicode, reducing the limit to 70 characters per part.
tointegeryesID of the contact list to send to (from /list/list)
scheduled_timestring (date-time)Schedule the send for a future date/time (ISO 8601). Omit or leave empty to send immediately.
shorten_urlsbooleanSet to true to replace each link of the message with a short link https://mailp.ro/m/...: fewer characters, so sometimes fewer billed SMS parts. A link that cannot be shortened stays as is.

Responses

CodeDescription
200Bulk SMS send created successfully
202Insufficient SMS credits
400Missing required field
401Invalid credentials

Example 200

{
  "Id": 6001,
  "Message": "Flash sale today only — 30% off all orders. Shop now at mailpro.com/shop",
  "ScheduledTime": "2026-04-20T10:00:00",
  "To": [
    "42"
  ]
}

Example 202

{
  "Error": "Insufficient Credit",
  "Code": 202
}

Example 400

{
  "Error": "Malformed Input",
  "Code": 103
}

GET /send/add_single.{format}

Send a single SMS (GET)

Sends a single SMS to one recipient via a GET request. Useful for simple integrations where POST is not available. Credentials and message are passed as query parameters.

Note: avoid using GET for sensitive messages — query parameters appear in server logs. Prefer POST /send/add_single instead.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
toquerystringyesRecipient phone number. Accepts +41…, 0041… or 41… with or without separators. See Phone number format in the API description.
messagequerystringyesSMS message text (max 160 chars for standard encoding)
scheduled_timequerystring (date-time)Schedule the send (ISO 8601). Omit to send immediately.
shorten_urlsquerybooleanSet to true to replace each link of the message with a short link https://mailp.ro/m/...: fewer characters, so sometimes fewer billed SMS parts. A link that cannot be shortened stays as is.

Responses

CodeDescription
200SMS sent (or scheduled) successfully
202Insufficient SMS credits
400Missing required parameter
401Invalid credentials

Example 200

{
  "Id": 5001,
  "Message": "Your appointment is confirmed for tomorrow at 10:00.",
  "ScheduledTime": "2026-04-15T09:00:00",
  "To": "0041791234567",
  "Charge": "1"
}

POST /send/add_single.{format}

Send a single SMS

Sends a single SMS message to one recipient phone number. Supports scheduling via scheduled_time.

Credit consumption: credits are deducted at send time. The Charge field in the response shows how many credits were consumed.

The response returns { "Error": "Insufficient Credit", "Code": 202 } if the account has insufficient credits.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
messagestringyesSMS message text
tostringyesRecipient phone number. Accepts +41…, 0041… or 41… with or without separators. See Phone number format in the API description.
scheduled_timestring (date-time)Schedule the send for a future time. Omit to send immediately.
shorten_urlsbooleanSet to true to replace each link of the message with a short link https://mailp.ro/m/...: fewer characters, so sometimes fewer billed SMS parts. A link that cannot be shortened stays as is.

Responses

CodeDescription
200SMS sent (or scheduled) successfully
202Insufficient SMS credits
400Missing required field
401Invalid credentials

Example 200

{
  "Id": 5001,
  "Message": "Your verification code is 8472. Valid for 10 minutes.",
  "ScheduledTime": "2026-04-15T14:30:00",
  "To": "0041791234567",
  "Charge": "1"
}

Example 202

{
  "Error": "Insufficient Credit",
  "Code": 202
}

Example 400

{
  "Error": "Malformed Input",
  "Code": 103
}

GET /send/list.{format}

List SMS campaigns

Returns the list of SMS campaigns (bulk sends) for the account. Pagination via NumberOfRecords and PageNumber headers.

Use type_to to filter by send type:

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
type_toqueryinteger: 0, 1Send type filter: - 0 (default) — bulk sends to a contact list - 1 — individual single-number sends

Responses

CodeDescription
200Pending sends returned successfully (a plain array, empty when there is nothing waiting). Only sends still scheduled in the future are listed.
401Invalid credentials

Example 200

[
  {
    "Id": 5001,
    "Message": "Your verification code is 8472",
    "ScheduledTime": "2026-04-15T09:00:00",
    "To": "41791234567"
  }
]

POST /send/del.{format}

Cancel or delete an SMS send

Cancels a pending scheduled SMS send, or deletes a completed one from history. Only future-scheduled sends can be cancelled. Sends in progress cannot be stopped.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
id_sendintegeryesID of the SMS send to cancel or delete (from /send/list)

Responses

CodeDescription
200SMS send cancelled or deleted successfully
400Missing id_send
401Invalid credentials
500Delete failed (send not found or already processed)

Example 200

{
  "Result": "OK"
}

Example 500

{
  "Error": "Delete failed",
  "Code": 500
}

GET /send/scheduled.{format}

List my scheduled SMS sends

Returns the SMS sends (single or campaign) scheduled for a future date that have not yet been dispatched. Useful before calling /cancel or /reschedule.

Records are sorted by scheduled_time ascending.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
id_clientqueryintegeryes
api_keyquerystringyes
NumberOfRecordsheaderintegerItems per page — 5,000 by default and at most (see Pagination). HTTP header or query parameter.
PageNumberheaderinteger1-based page number for paginated responses. Sent as HTTP header.

Responses

CodeDescription
200List of scheduled SMS sends
401Invalid credentials

Example 200

[
  {
    "Id": 9001,
    "Message": "Black Friday: 30% off until midnight.",
    "ScheduledTime": "2026-11-27T12:00:00",
    "To": "+33671234567"
  }
]

POST /send/{id_send}/cancel.{format}

Cancel a scheduled SMS send

Cancels a scheduled SMS that has not yet been dispatched. If the send has already been processed (or doesn't exist / belongs to another client), returns 409 Conflict.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
id_sendpathintegeryes

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryes
api_keystringyes

Responses

CodeDescription
200Send cancelled
401Invalid credentials
409Already dispatched or not found

Example 200

{
  "Result": "OK",
  "Cancelled": 9001
}

Example 409

{
  "error": "conflict",
  "message": "Send not found, not owned by client, or already dispatched."
}

PATCH /send/{id_send}/reschedule.{format}

Reschedule a scheduled SMS send

Updates the planned date of a scheduled SMS that has not yet been dispatched. New date must be in the future and within 90 days.

Date field name: the API accepts scheduled_time (primary) as well as the legacy aliases PlanDate, date_planned, and DatePlanned. Provide any one of them — the first non-null is used.

OAuth scope : sms:send

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
id_sendpathintegeryes

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryes
api_keystringyes
scheduled_timestring (date-time)Primary field name.
PlanDatestring (date-time)Legacy alias accepted for backward compatibility.
date_plannedstring (date-time)Legacy alias accepted for backward compatibility.
DatePlannedstring (date-time)Legacy alias accepted for backward compatibility.

Responses

CodeDescription
200Send rescheduled
400Missing or invalid scheduled_time
401Invalid credentials
409Already dispatched, not found, or new date out of range

Example 200

{
  "Result": "OK",
  "Id": 9001,
  "NewScheduledTime": "2026-12-31T14:30:00"
}

Example 409

{
  "error": "conflict",
  "message": "Reschedule failed — send not found, already dispatched, or new date out of range."
}

Lists

Manage SMS contact lists. A contact list groups phone numbers for bulk sending. You can create up to 1,000 lists per account (same limit on the three Mailpro APIs and in the app).

GET /list/list.{format}

List phone contact lists

Returns all SMS contact lists for the account. Use the returned Id values when sending bulk SMS campaigns or adding phone numbers.

OAuth scope : sms:contacts:read

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Responses

CodeDescription
200Phone lists returned successfully
401Invalid credentials

Example 200

{
  "Items": [
    {
      "AddressBookId": 42,
      "Name": "Newsletter subscribers",
      "TotalNumberPhones": 1547
    },
    {
      "AddressBookId": 43,
      "Name": "Loyalty program",
      "TotalNumberPhones": 823
    }
  ]
}

POST /list/add.{format}

Create a contact list

Creates a new SMS contact list with the given name. The list starts empty — add phone numbers with POST /phone/add. Maximum 1,000 lists per account (same limit on the three Mailpro APIs and in the app). Returns HTTP 422 if the limit is reached.

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
namestringyesDisplay name for the new contact list

Responses

CodeDescription
200Contact list created successfully
400Missing required field (name)
401Invalid credentials

Example 200

{
  "Id": 44,
  "Name": "Spring campaign 2026",
  "NumberPhones": 0
}

Example 400

{
  "Error": "Malformed Input",
  "Code": 103
}

POST /list/edit.{format}

Rename a contact list

Updates the display name of an existing SMS contact list. The phone numbers in the list are not affected.

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
address_book_idintegeryesID of the contact list to rename (from /list/list)
namestringyesNew display name for the contact list

Responses

CodeDescription
200Contact list renamed successfully
400Missing required field
401Invalid credentials

POST /list/del.{format}

Delete a contact list

Permanently deletes an SMS contact list and all the phone numbers it contains. This action cannot be undone.

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
address_book_idintegeryesID of the contact list to delete

Responses

CodeDescription
200Contact list deleted successfully
400Missing address_book_id
401Invalid credentials

Phone Numbers

Manage individual phone numbers within a contact list — add, update, and remove entries.

GET /phone/list.{format}

List phone numbers in a contact list

Returns a paginated list of phone numbers in a specific contact list. Use address_book_id to specify which list to retrieve. Pagination: NumberOfRecords and PageNumber (5,000 per page by default, page 1).

OAuth scope : sms:contacts:read

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format
address_book_idqueryintegeryesID of the contact list to retrieve phone numbers from
NumberOfRecordsheaderintegerItems per page — 5,000 by default and at most (see Pagination). HTTP header or query parameter.
PageNumberheaderinteger1-based page number for paginated responses. Sent as HTTP header.
SortByNameheaderbooleanSet to true to sort results alphabetically by name.

Responses

CodeDescription
200Phone numbers returned successfully
401Invalid credentials

Example 200

{
  "Items": [
    {
      "Id": 1001,
      "Number": "41791234567",
      "FirstName": "Alice",
      "LastName": "Dupont"
    },
    {
      "Id": 1002,
      "Number": "33612345678",
      "FirstName": "Bob",
      "LastName": "Martin"
    }
  ]
}

POST /phone/add.{format}

Add phone number(s) to a list

Adds one or more phone numbers to a contact list.

Single number: use the number field.

Bulk import: use the phone_list field with numbers separated by semicolons: +41791234567;+33612345678;0049301234567

Phone numbers accept +, 00 or bare format — see Phone number format in the API description for the full list of accepted / rejected inputs. Duplicate numbers are silently skipped unless force=1 is set.

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
address_book_idintegeryesID of the contact list to add the number(s) to
numberstringSingle phone number. Accepts +41…, 0041… or 41… with or without separators (spaces, dashes, dots, slashes, parentheses). See Phone number format in the API description. Use this OR phone_list — not both.
phone_liststringSemicolon-separated list of phone numbers for bulk import. Use this OR number — not both. Example: 0041791234567;0033612345678
firstnamestringFirst name of the contact (optional, single number only)
lastnamestringLast name of the contact (optional, single number only)
forceinteger: 0, 1Set to 1 to add a number even if it was previously unsubscribed or already exists. Default: 0 (duplicates are skipped).

Responses

CodeDescription
200Phone number(s) added successfully
400Missing required field
401Invalid credentials

Example 200

{
  "Id": 1003,
  "Number": "0041791234567",
  "FirstName": "Alice",
  "LastName": "Dupont"
}

POST /phone/edit.{format}

Update a phone number entry

Updates the phone number and/or contact details of an existing entry. Use number_id (from /phone/list) to identify the entry to update. Only fields provided in the request are updated.

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
number_idintegeryesID of the phone number entry to update (from /phone/list)
numberstringNew phone number. Accepts +41…, 0041… or 41… with or without separators. See Phone number format in the API description.
firstnamestringNew first name for the contact
lastnamestringNew last name for the contact

Responses

CodeDescription
200Phone number entry updated successfully
400Missing number_id
401Invalid credentials

POST /phone/del.{format}

Remove a phone number from a list

Permanently removes a specific phone number entry from its contact list. Use number_id (from /phone/list) to identify the entry.

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (application/x-www-form-urlencoded)

NameTypeRequiredDescription
id_clientintegeryesYour Mailpro client ID
api_keystringyesYour API key (GUID)
number_idintegeryesID of the phone number entry to delete (from /phone/list)

Responses

CodeDescription
200Phone number removed successfully
400Missing number_id
401Invalid credentials

Credit

Check the remaining SMS credit balance for your account (separate from the monthly API request quota — see /account/limits).

GET /credit/get.{format}

Get SMS credit balance

Returns the current SMS credit balance for your account. SMS credits are consumed at send time. One standard SMS (≤160 GSM-7 characters) costs 1 credit. Longer messages or messages with special characters may cost more.

> Note: this returns your SMS send credit balance, not your API request quota. > For the API quota see GET /account/limits.{format}.

OAuth scope : sms:read

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Responses

CodeDescription
200Credit balance returned successfully
401Invalid credentials

Example 200

{
  "TotalCredits": 5000
}

History

Browse the complete log of past SMS campaigns.

GET /history/list.{format}

List SMS sending history

Returns a paginated log of all past SMS campaigns sent from this account. Results are ordered by date descending (most recent first). Pagination: NumberOfRecords and PageNumber (headers or query, 5,000 per page by default).

OAuth scope : sms:read

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Responses

CodeDescription
200History list returned successfully
401Invalid credentials

Example 200

{
  "Items": [
    {
      "Id": 583294,
      "DateSent": "2026-07-17T18:56:39.813",
      "Message": "Your verification code is 8472",
      "Charge": 3,
      "Parts": 1
    }
  ]
}

Import

Upload a CSV or XLSX file to import phone numbers into a contact list in bulk. The file is queued for asynchronous processing — track completion via the ImportJobId returned or via the optional webhook_url callback.

POST /import/upload.{format}

Upload a phone-numbers file (CSV / XLSX) for bulk import

Upload a CSV or XLSX file to import phone numbers into a contact list. The file is stored and queued for asynchronous processing — the endpoint returns an ImportJobId immediately.

Request type: multipart/form-data

Required form fields:

Optional:

File format:

OAuth scope : sms:contacts:write

Parameters

NameInTypeRequiredDescription
formatpathstring: json, xmlyesResponse format

Request body (multipart/form-data)

NameTypeRequiredDescription
id_listinteger (int64)yesID of the destination contact list
filestring (binary)yesCSV or XLSX file (UTF-8, max 50 MB)
webhook_urlstring (uri)Callback URL invoked when processing finishes

Responses

CodeDescription
200File accepted and queued
400No file uploaded or missing id_list
401Invalid credentials
500Server or storage error

Example 200

{
  "Result": "OK",
  "ImportJobId": 15,
  "InternalName": "230575-20260420142616-phones.csv"
}

Webhooks

Subscribe your server to real-time SMS event notifications. Mailpro POSTs an HMAC-signed JSON payload to your URL as soon as the subscribed event happens. See the "Webhooks" section in the introduction for the full event catalog, payload envelope, signature verification snippets, and retry policy.

GET /webhooks

List webhooks

Returns every webhook configured on the authenticated account.

Responses

CodeDescription
200Webhooks of the account
401Invalid credentials

Example 200

{
  "items": [
    {
      "id": 14,
      "url": "https://example.com/hooks/mailpro",
      "description": "Slack integration",
      "is_active": true,
      "created_at": "2026-07-01T21:09:52.43",
      "updated_at": "2026-07-21T18:56:08.02",
      "last_delivery_at": "2026-07-21T18:56:07.653",
      "last_delivery_status": 200,
      "consecutive_failures": 0,
      "events": [
        "sms.delivered",
        "sms.failed"
      ]
    }
  ],
  "total": 1
}

POST /webhooks

Create a webhook

Creates a new webhook subscription. The response contains a secret that is shown only once — store it immediately, server-side. Use it to verify the HMAC signature of every incoming payload.

Limits: max 20 webhooks per account, max 50 events per webhook.

Request body (application/json)

NameTypeRequiredDescription
urlstring (uri)yesHTTPS endpoint (HTTP refused in production)
eventsarray of stringyesList of event types to subscribe to (see catalog above). Use ["*"] to subscribe to all events of this API.
descriptionstring

Example

{
  "url": "https://example.com/hooks/mailpro",
  "events": [
    "sms.delivered",
    "sms.failed"
  ],
  "description": "Slack integration"
}

Responses

CodeDescription
201Webhook created — secret is returned only here
400Invalid URL, events list, or limit exceeded
401Invalid credentials

Example 201

{
  "id": 42,
  "url": "https://example.com/hooks/mailpro",
  "events": [
    "sms.delivered",
    "sms.failed"
  ],
  "description": "Slack integration",
  "isActive": true,
  "consecutiveFailures": 0,
  "autoDisabledAt": null,
  "autoDisabledReason": null,
  "createdAt": "2026-05-25T10:00:00Z",
  "updatedAt": "2026-05-25T10:00:00Z",
  "secret": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
}

GET /webhooks/{id}

Get a webhook

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes

Responses

CodeDescription
200The webhook
404Webhook not found

PUT /webhooks/{id}

Update a webhook

Partial update — only the sent fields are modified.

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes

Request body (application/json)

NameTypeRequiredDescription
urlstring (uri)
eventsarray of string
descriptionstring
isActivebooleanSet true to re-enable an auto-disabled webhook once your endpoint is fixed.

Responses

CodeDescription
200Updated webhook
400Invalid payload
404Webhook not found

DELETE /webhooks/{id}

Delete a webhook

Permanently deletes the webhook and its full delivery history.

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes

Responses

CodeDescription
204Deleted
404Webhook not found

POST /webhooks/{id}/test

Send a test event

Queues an immediate ping event (or any other event type via the eventType body field) to your endpoint. Useful to verify reachability and signature verification before relying on real events.

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes

Request body (application/json)

NameTypeRequiredDescription
eventTypestring

Example

{
  "eventType": "ping"
}

Responses

CodeDescription
202Event queued for dispatch
404Webhook not found

Example 202

{
  "deliveryId": 1234,
  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
  "eventType": "ping"
}

POST /webhooks/{id}/rotate-secret

Rotate the HMAC secret

Generates a new HMAC secret and invalidates the old one immediately. The new secret is returned once in the response — store it. Every delivery from this point on will be signed with the new secret.

Use this if you suspect your secret has been compromised.

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes

Responses

CodeDescription
200New secret (visible once)
404Webhook not found

Example 200

{
  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
}

GET /webhooks/{id}/deliveries

List delivery attempts

Returns the history of dispatch attempts for this webhook (30-day retention). Useful for debugging — which events were sent, status codes received, retry counts, error messages.

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes
limitqueryinteger
cursorqueryinteger (int64)Pagination cursor (= last delivery ID seen). Returns deliveries with id < cursor.

Responses

CodeDescription
200Array of delivery attempts (newest first)
404Webhook not found

POST /webhooks/{id}/deliveries/{deliveryId}/replay

Replay a delivery

Queues a fresh delivery attempt with the same payload as the original. Useful to re-trigger a failed delivery after fixing your endpoint. A NEW Webhook_Delivery row is created (the original is preserved for audit). The replay goes through the standard retry policy (same backoff schedule, same 10-failure auto-disable rule).

Parameters

NameInTypeRequiredDescription
idpathinteger (int64)yes
deliveryIdpathinteger (int64)yes

Responses

CodeDescription
202Replay queued
404Webhook or delivery not found