Send SMS

Send one SMS, or the same SMS to many people, in a single request.

POST a JSON body containing a messages array. Each message has a sender, the text, and one or more recipients. The response tells you, recipient by recipient, whether the message was accepted and what it cost.

Method

POSThttps://api.everymessage.com/v1/submit

Send Content-Type: application/json and authenticate with HTTP Basic (details). The response is HTTP 200 even if the request is refused, so check responseStatusReason.

Request

Single

{
  "messages": [
    {
      "sender": "everymessage",
      "content": "Your appointment is confirmed for 10:30 tomorrow.",
      "recipient": [
        {
          "number": "447700900123"
        }
      ],
      "reference": "booking-1042",
      "registeredDelivery": true
    }
  ]
}

Many recipients

{
  "messages": [
    {
      "sender": "everymessage",
      "content": "Our office is closed on Monday for the bank holiday.",
      "recipient": [
        {
          "number": "447700900123"
        },
        {
          "number": "447700900456"
        },
        {
          "number": "447700900789"
        }
      ]
    }
  ]
}

Personalised

{
  "messages": [
    {
      "sender": "everymessage",
      "content": "Hi Sam, your order A1042 has shipped.",
      "recipient": [
        {
          "number": "447700900123"
        }
      ],
      "reference": "A1042"
    },
    {
      "sender": "everymessage",
      "content": "Hi Priya, your order A1043 has shipped.",
      "recipient": [
        {
          "number": "447700900456"
        }
      ],
      "reference": "A1043"
    }
  ]
}

Scheduled

{
  "scheduled": "2026-11-02T09:00:00Z",
  "expiry": 240,
  "replyUrl": "https://example.com/everymessage/receipts/your-token",
  "messages": [
    {
      "sender": "everymessage",
      "content": "Reminder: your MOT is due this week.",
      "recipient": [
        {
          "number": "447700900123"
        }
      ],
      "registeredDelivery": true
    }
  ]
}

Unicode

{
  "unicode": true,
  "messages": [
    {
      "sender": "everymessage",
      "content": "Zamówienie gotowe do odbioru 🎉",
      "recipient": [
        {
          "number": "48600900123"
        }
      ]
    }
  ]
}

To personalise, send one message per recipient in the same request, as in the Personalised example. Each message is billed and reported separately.

Request body

FieldTypeDescription
messages requiredarrayThe messages to send. See Message below.
scheduledstringSend later. ISO 8601 date and time in UTC, for example 2026-11-02T09:00:00Z. Applies to every message in the request. Omit it, or give a time in the past, to send now.
expiryintegerHow long the network keeps trying to deliver, in minutes. Default 2880 (48 hours); allowed 5–4320. Values outside the range are clamped.
unicodebooleanDefault false: text is converted to the standard SMS alphabet (curly quotes and dashes become plain ones, accents and emoji are removed), 160 characters per part. Set true for emoji or non-Latin text, 70 characters per part. See SMS character limits explained.
replyUrlstringWhere to send delivery receipts for this request by webhook. Overrides your account default. See delivery receipts.

Message

FieldTypeDescription
sender requiredstringWho the message is from: up to 11 letters and digits (for example everymessage), or a number you own in international format (for example 447700900000). Use a number if you want replies.
content requiredstringThe message text. Long messages are sent in several parts and joined on the handset.
recipient requiredarrayOne or more {"number": "447700900123"} objects. Numbers are in international format, without + or leading zeros.
referencestringYour own reference, up to 64 characters. It comes back on the delivery receipt.
registeredDeliverybooleanSet true to receive a delivery receipt. Default false.

A simpler query-string form, GET /v1/submit?sender=…&content=…&recipient=…, sends a single message. See the full API reference.

Response

{
  "apiName": "everymessage Web API",
  "apiVersion": "1.0.2",
  "apiTime": "11 October 2026 10:30:00",
  "apiState": "RUNNING",
  "responseStatusCode": 200,
  "processingTime": 58,
  "body": {
    "submissions": [
      {
        "id": 48211,
        "status": "SUCCESS",
        "recipient": "447700900123",
        "sender": "everymessage",
        "content": "",
        "segments": 1,
        "charged": 0.04
      },
      {
        "id": 0,
        "status": "INVALID_MOBILE_NUMBER",
        "recipient": "4477009",
        "sender": "everymessage",
        "content": "",
        "segments": 0,
        "charged": 0
      }
    ],
    "balance": 1249.96,
    "charged": 0.04
  }
}

Response body

FieldTypeDescription
submissionsarrayOne entry per recipient, in the order sent.
chargednumberTotal cost of the request.
balancenumberRemaining credit, for prepay accounts.

Submission

FieldTypeDescription
idintegerMessage id. Keep it: delivery receipts refer to it.
statusstringSUCCESS if accepted for delivery, otherwise the reason below.
recipientstringThe number, in international format.
senderstringThe sender used.
segmentsintegerNumber of SMS parts. You are charged per part.
chargednumberCost for this recipient.

A value that does not apply may be left out of the response, so treat every field as optional.

Submission status

statusMeaning
SUCCESSAccepted and queued for delivery.
INVALID_MOBILE_NUMBERThe number is not a valid mobile number.
MISSING_MOBILE_NUMBERNo number was given.
BLOCKED_MOBILE_NUMBERThe number is on a block list, for example because it opted out.
EMPTY_MESSAGEThere was no text left to send, for example an emoji-only message sent without unicode.
ORIGINATOR_NOT_ALLOWEDThe sender is not valid or not allowed on your account.
ROUTE_NOT_SUPPORTEDYour account is not set up to send to that country.
TOO_MANY_SEGMENTSThe message is longer than your account allows.
FAILUREThe message could not be accepted.

Code examples

Both examples read the keys from the EM_API_KEY and EM_SECRET_KEY environment variables. The C# example needs .NET 8 or later and no extra packages; the Python example needs Python 3.10 or later and pip install httpx.

C#

// Send an SMS with the everymessage v1 API (.NET 8 or later)
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

var apiKey = Environment.GetEnvironmentVariable("EM_API_KEY")!;
var secretKey = Environment.GetEnvironmentVariable("EM_SECRET_KEY")!;

using var http = new HttpClient { BaseAddress = new Uri("https://api.everymessage.com/") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{apiKey}:{secretKey}")));

var json = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

var request = new SubmitRequest(
[
    new Message(
        Sender: "everymessage",
        Content: "Your appointment is confirmed for 10:30 tomorrow.",
        Recipient: [new Recipient("447700900123")],
        Reference: "booking-1042",
        RegisteredDelivery: true)
]);

using var response = await http.PostAsJsonAsync("v1/submit", request, json);
response.EnsureSuccessStatusCode();

var result = await response.Content.ReadFromJsonAsync<ApiEnvelope<SubmitBody>>(json)
             ?? throw new InvalidOperationException("Empty response from everymessage");

// The API returns HTTP 200 even on errors: check responseStatusReason.
if (result.ResponseStatusReason is not null)
    throw new InvalidOperationException($"Submit failed: {result.ResponseStatusReason}");

foreach (var s in result.Body!.Submissions)
    Console.WriteLine($"{s.Recipient}: {s.Status} (id {s.Id}, {s.Segments ?? 0} part(s))");

Console.WriteLine($"Charged {result.Body.Charged}, balance {result.Body.Balance}");

record SubmitRequest(IReadOnlyList<Message> Messages);
record Message(string Sender, string Content, IReadOnlyList<Recipient> Recipient,
    string? Reference = null, bool RegisteredDelivery = false);
record Recipient(string Number);

record ApiEnvelope<T>(int ResponseStatusCode, string? ResponseStatusReason, int ProcessingTime, T? Body);
// Fields with no value are left out of the response, so keep them nullable.
record SubmitBody(decimal? Balance, decimal? Charged, IReadOnlyList<Submission> Submissions);
record Submission(long Id, string Status, string Recipient, string? Sender,
    int? Segments, decimal? Charged);

Python

"""Send an SMS with the everymessage v1 API (Python 3.10+, pip install httpx)."""
import os

import httpx

payload = {
    "messages": [
        {
            "sender": "everymessage",
            "content": "Your appointment is confirmed for 10:30 tomorrow.",
            "recipient": [{"number": "447700900123"}],
            "reference": "booking-1042",
            "registeredDelivery": True,
        }
    ]
}

with httpx.Client(
    base_url="https://api.everymessage.com",
    auth=(os.environ["EM_API_KEY"], os.environ["EM_SECRET_KEY"]),
    timeout=30,
) as client:
    response = client.post("/v1/submit", json=payload)
    response.raise_for_status()
    result = response.json()

# The API returns HTTP 200 even on errors: check responseStatusReason.
if reason := result.get("responseStatusReason"):
    raise RuntimeError(f"Submit failed: {reason}")

body = result["body"]
# Fields with no value are left out of the response, so read them with .get().
for s in body["submissions"]:
    print(f"{s['recipient']}: {s['status']} (id {s['id']}, {s.get('segments', 0)} part(s))")
print(f"Charged {body.get('charged')}, balance {body.get('balance')}")