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
https://api.everymessage.com/v1/submitSend 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
| Field | Type | Description |
|---|---|---|
messages required | array | The messages to send. See Message below. |
scheduled | string | Send 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. |
expiry | integer | How long the network keeps trying to deliver, in minutes. Default 2880 (48 hours); allowed 5–4320. Values outside the range are clamped. |
unicode | boolean | Default 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. |
replyUrl | string | Where to send delivery receipts for this request by webhook. Overrides your account default. See delivery receipts. |
Message
| Field | Type | Description |
|---|---|---|
sender required | string | Who 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 required | string | The message text. Long messages are sent in several parts and joined on the handset. |
recipient required | array | One or more {"number": "447700900123"} objects. Numbers are in international format, without + or leading zeros. |
reference | string | Your own reference, up to 64 characters. It comes back on the delivery receipt. |
registeredDelivery | boolean | Set 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
| Field | Type | Description |
|---|---|---|
submissions | array | One entry per recipient, in the order sent. |
charged | number | Total cost of the request. |
balance | number | Remaining credit, for prepay accounts. |
Submission
| Field | Type | Description |
|---|---|---|
id | integer | Message id. Keep it: delivery receipts refer to it. |
status | string | SUCCESS if accepted for delivery, otherwise the reason below. |
recipient | string | The number, in international format. |
sender | string | The sender used. |
segments | integer | Number of SMS parts. You are charged per part. |
charged | number | Cost for this recipient. |
A value that does not apply may be left out of the response, so treat every field as optional.
Submission status
| status | Meaning |
|---|---|
SUCCESS | Accepted and queued for delivery. |
INVALID_MOBILE_NUMBER | The number is not a valid mobile number. |
MISSING_MOBILE_NUMBER | No number was given. |
BLOCKED_MOBILE_NUMBER | The number is on a block list, for example because it opted out. |
EMPTY_MESSAGE | There was no text left to send, for example an emoji-only message sent without unicode. |
ORIGINATOR_NOT_ALLOWED | The sender is not valid or not allowed on your account. |
ROUTE_NOT_SUPPORTED | Your account is not set up to send to that country. |
TOO_MANY_SEGMENTS | The message is longer than your account allows. |
FAILURE | The 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')}")
