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

FieldDescription
idUnique identifier, prefixed msg_.
statusOne of queued, sending, sent, delivered, undelivered, failed. See delivery status.
to / fromRecipient in E.164; sender ID, short code, or number.
bodyThe message text (UTF-8).
segmentsNumber of SMS segments the body was split into.
directionoutbound or inbound.
priceCharge for the message once known, as a decimal string, with price_currency.
error_codeSet when a message is undelivered or failed. See Errors.
created_atRFC 3339 timestamp.

Send a message

POST/v1/messages
ParameterDescription
to stringREQUIREDRecipient phone number in E.164.
from stringREQUIREDA sender ID, short code, or one of your provisioned numbers.
body stringREQUIREDMessage text. Long bodies are segmented automatically.
channel stringOPTIONALDefaults to sms.
type stringOPTIONALtransactional (default) or promotional. Affects routing and quiet-hours handling.
status_callback stringOPTIONALURL to receive delivery status webhooks for this message.
reference stringOPTIONALYour own identifier, echoed back on the message and its webhooks.
send_at stringOPTIONALRFC 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

GET/v1/messages/{id}

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

GET/v1/messages

Returns messages in reverse-chronological order. Cursor-paginated (see conventions). Filter with the parameters below.

ParameterDescription
to OPTIONALOnly messages to this number.
status OPTIONALFilter by delivery status.
direction OPTIONALinbound or outbound.
created_after / created_before OPTIONALRFC 3339 time bounds.
limit / starting_after OPTIONALPagination 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"
  }
}
Opt-outs are handled for you. Standard keywords like 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?" }
Outbound that can hold a conversation. Send a campaign or reminder with Send a message, then attach an agent to the sending number so any reply is understood and handled — a reschedule, a question, an opt-out — instead of landing in a dead inbox.

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.

StatusMeaning
queuedAccepted and waiting to be routed.
sendingHanded to a carrier.
sentAccepted by the carrier; not yet confirmed at the handset.
deliveredConfirmed delivered to the handset.
undeliveredCarrier reported it could not be delivered; see error_code.
failedRejected 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.