MESSAGING
Messaging (SMS)
Send one-off and high-volume SMS, receive replies, and track delivery per message. Messages route across multiple carriers automatically, so a degraded route doesn't cost you a delivery.
The message object
| Field | Description |
|---|---|
id | Unique identifier, prefixed msg_. |
status | One of queued, sending, sent, delivered, undelivered, failed. See delivery status. |
to / from | Recipient in E.164; sender ID, short code, or number. |
body | The message text (UTF-8). |
segments | Number of SMS segments the body was split into. |
direction | outbound or inbound. |
price | Charge for the message once known, as a decimal string, with price_currency. |
error_code | Set when a message is undelivered or failed. See Errors. |
created_at | RFC 3339 timestamp. |
Send a message
| Parameter | Description |
|---|---|
to stringREQUIRED | Recipient phone number in E.164. |
from stringREQUIRED | A sender ID, short code, or one of your provisioned numbers. |
body stringREQUIRED | Message text. Long bodies are segmented automatically. |
channel stringOPTIONAL | Defaults to sms. |
type stringOPTIONAL | transactional (default) or promotional. Affects routing and quiet-hours handling. |
status_callback stringOPTIONAL | URL to receive delivery status webhooks for this message. |
reference stringOPTIONAL | Your own identifier, echoed back on the message and its webhooks. |
send_at stringOPTIONAL | RFC 3339 time to schedule the send. |
Request
curl https://api.atommatrix.ai/v1/messages \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f2b9c1e-9d3a-4b8e-8a1c-2f6d0e4a7b31" \
-d '{
"to": "+14155550123",
"from": "ATOMMTX",
"type": "transactional",
"body": "Your code is 481920. It expires in 10 minutes.",
"status_callback": "https://example.com/hooks/atommatrix"
}'
Response 201 Created
{
"id": "msg_01HN9K7QophZ8",
"object": "message",
"channel": "sms",
"direction": "outbound",
"to": "+14155550123",
"from": "ATOMMTX",
"body": "Your code is 481920. It expires in 10 minutes.",
"status": "queued",
"segments": 1,
"reference": null,
"created_at": "2026-07-07T12:00:00Z"
}
Retrieve a message
Fetch the current state of a message, including its latest status, price, and any error_code.
curl https://api.atommatrix.ai/v1/messages/msg_01HN9K7QophZ8 \
-H "Authorization: Bearer sk_live_your_key"
List messages
Returns messages in reverse-chronological order. Cursor-paginated (see conventions). Filter with the parameters below.
| Parameter | Description |
|---|---|
to OPTIONAL | Only messages to this number. |
status OPTIONAL | Filter by delivery status. |
direction OPTIONAL | inbound or outbound. |
created_after / created_before OPTIONAL | RFC 3339 time bounds. |
limit / starting_after OPTIONAL | Pagination controls. |
Receive inbound messages
When someone replies to one of your numbers, AtomMatrix delivers a message.received event to your configured webhook endpoint. Use it to power two-way conversations, keyword handling (STOP, HELP), or to hand the thread to an AI agent.
{
"id": "evt_01HN9M...",
"type": "message.received",
"created_at": "2026-07-07T12:03:10Z",
"data": {
"id": "msg_01HN9M2R...",
"object": "message",
"direction": "inbound",
"from": "+14155550123",
"to": "ATOMMTX",
"body": "STOP"
}
}
STOP and START update the recipient's consent state automatically and are enforced on future sends. You still receive the event so you can update your own records.Answer with an AI agent
SMS becomes two-way the moment you put an AI agent behind a number. The agent reads each inbound message, looks things up with your tools, and replies over SMS automatically — no polling, no reply loop to build. There are two ways to wire it up.
Option A — attach an agent to a number
Assign a live agent to one of your numbers in the console. Every inbound message to that number opens (or continues) a conversation and triggers an agent run; the reply is sent back over SMS for you. No extra code — you just keep receiving message.received and run.completed events for your records.
Option B — drive it from the API
For full control, open a conversation on the sms channel and post the inbound text as a customer message. Because the channel is sms, the agent's reply is delivered over Messaging automatically — the same segmentation, routing, and delivery receipts as any other send.
// 1. On message.received, start (or reuse) an SMS conversation:
POST /v1/conversations
{ "agent_id": "agt_support_en", "channel": "sms",
"customer": { "phone": "+14155550123" } }
// 2. Forward the customer's text — the agent replies over SMS itself:
POST /v1/conversations/cnv_01HN9V.../messages
{ "role": "customer", "content": "Where is my order 10842?" }
Delivery status
An outbound message moves through a predictable set of states. The final state is reported to your status_callback (or account webhook) as a message.updated event, and is always readable by retrieving the message.
| Status | Meaning |
|---|---|
queued | Accepted and waiting to be routed. |
sending | Handed to a carrier. |
sent | Accepted by the carrier; not yet confirmed at the handset. |
delivered | Confirmed delivered to the handset. |
undelivered | Carrier reported it could not be delivered; see error_code. |
failed | Rejected before sending (bad number, no route, blocked). |
Not every carrier returns handset-level receipts; where they don't, sent is the terminal success state. See Errors & limits for error_code values.