Send an SMS or MMS message
curl --request POST \ --url https://api.sipstack.com/api/v2/messages/send \ --header 'Content-Type: application/json' \ --header 'x-api-key: <x-api-key>' \ --data '{ "to": "+14165550100", "from": "+16135550200", "message": "Hi! Your appointment is confirmed for tomorrow at 2pm." }'import requests
url = "https://api.sipstack.com/api/v2/messages/send"
payload = { "to": "+14165550100", "from": "+16135550200", "message": "Hi! Your appointment is confirmed for tomorrow at 2pm."}headers = { "x-api-key": "<x-api-key>", "Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())const url = 'https://api.sipstack.com/api/v2/messages/send';const options = { method: 'POST', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, body: '{"to":"+14165550100","from":"+16135550200","message":"Hi! Your appointment is confirmed for tomorrow at 2pm."}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import axios from 'axios';
const options = { method: 'POST', url: 'https://api.sipstack.com/api/v2/messages/send', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, data: { to: '+14165550100', from: '+16135550200', message: 'Hi! Your appointment is confirmed for tomorrow at 2pm.' }};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}Sends an outbound SMS — or an MMS when media is supplied — from one of
your organization’s numbers through Flare (transactional / A2P).
Authenticated with an API key (sms:send scope). Subject to your plan’s
message allowance and the per-client rate limit — see
Rate Limits.
This path is an alias: the canonical, product-scoped path is
POST /api/v2/flare/messages, and the two have identical behaviour.
Sending requires a Flare Pro-or-above plan with an active or
trialing Flare subscription, and the from number must be a Flare
A2P (team inbox) number. A request that fails any of these is
refused with 403.
Attaching MMS media
There are three ways to attach media, and they may be combined. The total number of media parts per message is at most 10.
| Way | Where | Field |
|---|---|---|
| Hosted URLs (the carrier fetches them) | JSON body | media — also accepted as mediaUrls, or a single mediaUrl |
| Uploaded files, binary | multipart/form-data | media, one file part per file |
| Uploaded files, base64 | JSON body | mediaFiles |
Upload limits. Each uploaded file is at most 3,500,000 bytes
(3.5 MB), and all uploaded files in one message are at most
3,500,000 bytes in total — Bandwidth’s documented MMS ceiling, so a
larger payload cannot be delivered by the carrier. Accepted upload
types are image/jpeg, image/png and image/gif, and only these;
the declared type must be in that list and must match the file’s
actual magic bytes. Video and audio MMS, and image/webp, are not
currently accepted. Hosted URLs are not type-checked by SIPSTACK — the
carrier fetches and validates them.
Uploading uses the same authorization, plan gating and metering as
the hosted URL path. Uploaded media is stored in your organization’s
regional object storage and handed to the carrier as a short-lived
signed URL; nothing is stored until the message passes validation,
entitlement and quota checks, so a rejected send stores nothing. The
media_urls returned here and by GET /api/v2/messages and
GET /api/v2/messages/{id} are 24-hour signed URLs for uploaded
media, and the URLs exactly as supplied for hosted media.
An MMS bills a flat minimum of 4 SMS segments regardless of how the media arrived.
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”Send an SMS, or an MMS when media is supplied. Either message or media
must be present (an MMS may carry media with no text).
Media can be attached two ways in a JSON body — hosted URLs
(media, which the carrier fetches) or uploaded files
(mediaFiles, base64). They may be combined, and the total number of
media parts is at most 10. To upload files as binary instead of
base64, post the same fields as multipart/form-data — see
SendMessageMultipartRequest.
object
Recipient phone number — 10 or 11 digits (a leading 1 is added to 10-digit numbers).
Message body. Long messages are split into segments which count against your plan allowance. Optional when media is present.
Sending number — must be one of your organization’s active numbers. Omit to use the organization’s first active number.
Up to 10 absolute HTTPS URLs to attach as MMS media (the carrier
fetches them server-side; non-HTTPS or unparseable URLs are rejected
with 400). Also accepted as mediaUrls or a single mediaUrl
string. An MMS bills a flat minimum of 4 SMS segments regardless
of body length (a longer text body still bills its larger computed
segment count).
The limit of 10 is the combined count of hosted URLs and uploaded files. Hosted URLs are not type-checked by SIPSTACK — the carrier fetches and validates them. Each URL is at most 2048 characters.
One uploaded MMS media file, carried as base64 in a JSON request body.
object
The file’s bytes, base64-encoded. May also be a full data URI
(data:image/png;base64,...), in which case contentType is
optional and is read from the URI. An empty file, invalid base64,
or a malformed entry is rejected with 400 MEDIA_MALFORMED.
Declared MIME type. Required unless data is a data URI that
carries one. It must be in the allowlist above (otherwise 400 MEDIA_TYPE_NOT_ALLOWED) and must match the file’s actual magic
bytes (otherwise 400 MEDIA_TYPE_MISMATCH) — a mismatched file is
never silently relabelled or transcoded. Video and audio MMS, and
image/webp, are not currently accepted.
Optional filename for the stored object. Has no effect on delivery.
One uploaded MMS media file, carried as base64 in a JSON request body.
object
The file’s bytes, base64-encoded. May also be a full data URI
(data:image/png;base64,...), in which case contentType is
optional and is read from the URI. An empty file, invalid base64,
or a malformed entry is rejected with 400 MEDIA_MALFORMED.
Declared MIME type. Required unless data is a data URI that
carries one. It must be in the allowlist above (otherwise 400 MEDIA_TYPE_NOT_ALLOWED) and must match the file’s actual magic
bytes (otherwise 400 MEDIA_TYPE_MISMATCH) — a mismatched file is
never silently relabelled or transcoded. Video and audio MMS, and
image/webp, are not currently accepted.
Optional filename for the stored object. Has no effect on delivery.
Examples
Plain SMS
{ "to": "+14165550100", "from": "+16135550200", "message": "Hi! Your appointment is confirmed for tomorrow at 2pm."}MMS from a hosted HTTPS URL
{ "to": "+14165550100", "message": "Here is your receipt.", "media": [ "https://cdn.example.com/receipt.jpg" ]}MMS from a base64 upload
{ "to": "+14165550100", "message": "Here is your receipt.", "mediaFiles": [ { "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", "contentType": "image/png", "filename": "receipt.png" } ]}A hosted URL and an upload in one message
{ "to": "+14165550100", "message": "Your receipt and our new catalogue.", "media": [ "https://cdn.example.com/receipt.jpg" ], "mediaFiles": [ { "data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", "filename": "catalogue.png" } ]}multipart/form-data body for sending an MMS with uploaded files.
Every text field is an ordinary form field; each file is a file part
under the field name media, repeated once per file.
Note the field naming: in a multipart form, media carries the file
parts and hosted links go in mediaUrls — whereas in a JSON body
media carries the hosted URLs. Uploads and hosted URLs may be
combined, up to 10 media parts in total.
object
Recipient phone number — 10 or 11 digits (a leading 1 is added to 10-digit numbers).
Example
+14165550100Message body. Optional when media is attached.
Example
Here is your receipt.Sending number — must be one of your organization’s active numbers. Omit to use the organization’s first active number.
Example
+16135550200Optional Flare contact id to associate the message with.
Example
8f3c2a10-5b7d-4e21-9a44-1c2f5b8e0d37File parts — repeat the media field once per file. Each file
is at most 3,500,000 bytes (3.5 MB), and all files in one
message are at most 3,500,000 bytes in total (Bandwidth’s MMS
ceiling — a larger payload cannot be delivered by the carrier).
Only image/jpeg, image/png and image/gif are accepted. Each
part’s declared Content-Type must be in that list and must
match the file’s actual magic bytes; a mismatch is rejected with
400, never silently relabelled or transcoded. Video and audio
MMS, and image/webp, are not currently accepted.
Hosted absolute HTTPS URLs, sent as ordinary text fields —
repeat the mediaUrls field once per URL. These behave exactly as
media does in a JSON body: the carrier fetches them, and SIPSTACK
does not type-check them.
Example
[ "https://cdn.example.com/receipt.jpg"]Responses
Section titled “ Responses ”Message accepted and sent to the carrier.
object
object
mms when the message carried media, otherwise sms.
The attached media URLs (empty for a plain SMS). For uploaded media these are time-limited signed URLs, valid for 24 hours; hosted URLs are returned exactly as supplied.
Examples
SMS accepted
{ "success": true, "message": "Message sent successfully", "data": { "messageId": "msg_1765432100000_a1b2c3d4e", "to": "+14165550100", "from": "+16135550200", "status": "sent", "type": "sms", "media_urls": [] }}Validation failure — missing to/message, invalid phone number
format, an invalid/inactive from number, or media that fails
validation. Media failures carry a machine-readable code.
Error shape returned by the send endpoint. code is present on media
validation failures and omitted on the older inline validation errors.
object
Machine-readable media validation code:
TOO_MANY_MEDIA— more than 10 media parts (hosted + uploaded).MEDIA_TOO_LARGE— a single file, or the total of all uploaded files, is over 3,500,000 bytes.MEDIA_TYPE_NOT_ALLOWED— the declared type is notimage/jpeg,image/pngorimage/gif.MEDIA_TYPE_MISMATCH— the file’s bytes are not what its declared type claims.MEDIA_MALFORMED— empty file, invalid base64, or a malformedmediaFilesentry.
See Error Codes.
Examples
Missing recipient
{ "success": false, "error": "Recipient phone number (to) is required"}More than 10 media parts
{ "success": false, "code": "TOO_MANY_MEDIA", "error": "A message may carry at most 10 media parts"}A file, or the total, over 3,500,000 bytes
{ "success": false, "code": "MEDIA_TOO_LARGE", "error": "Media exceeds the 3,500,000 byte limit"}Declared type not in the allowlist
{ "success": false, "code": "MEDIA_TYPE_NOT_ALLOWED", "error": "Unsupported media type image/webp — allowed types are image/jpeg, image/png, image/gif"}Bytes do not match the declared type
{ "success": false, "code": "MEDIA_TYPE_MISMATCH", "error": "File contents do not match the declared type image/png"}Empty file, invalid base64, or a malformed entry
{ "success": false, "code": "MEDIA_MALFORMED", "error": "Media file could not be decoded"}Missing or invalid API key.
Inline error shape used by the messaging API and management endpoints.
object
Examples
Missing or invalid API key
{ "success": false, "error": "Invalid API key"}Refused — API access is not enabled on your plan, the Flare plan is
below Pro or its subscription is not active/trialing, or the from
number is not a Flare A2P (team inbox) number. Applies identically
to hosted-URL and uploaded media.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}Rate limit or plan message allowance reached — the messaging quota is exhausted. Nothing is stored for a refused send.
Inline error shape used by the messaging API and management endpoints.
object
Examples
Rate limit reached
{ "success": false, "error": "Rate limit exceeded. Try again later."}Carrier send failed — the message is recorded with status failed.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}