Quickstart
This guide takes you from a new account to a delivered message. It assumes you already have a registered 10DLC campaign or a verified toll-free number. If you do not, start with Brands and campaigns first, because carriers block unregistered A2P traffic.
1. Get your API credentials
Create an API key pair in the console under Settings → API keys. You will get a key ID and a key secret. The secret is shown once and cannot be retrieved again.
export AO_KEY_ID="ao_live_k_7Fq2..."
export AO_KEY_SECRET="ao_live_s_9Xb4..."
Keys are scoped. A key with messages:write cannot read billing data, and a read-only key cannot send. Rotate or revoke a key at any time without downtime by creating the replacement first.
2. Confirm your sending number
List the numbers on your account and check that the one you want is attached to an approved campaign.
curl "https://api.anthonyoliva.com/v1/numbers" \
-u "$AO_KEY_ID:$AO_KEY_SECRET"
{
"data": [
{
"phone_number": "+13155550142",
"type": "10dlc",
"capabilities": ["sms", "mms"],
"campaign_id": "C7X4M2P",
"campaign_status": "approved"
}
]
}
If campaign_status is anything other than approved, messages will be rejected by the carrier. The status values are documented in Brands and campaigns.
3. Send a message
curl https://api.anthonyoliva.com/v1/messages \
-u "$AO_KEY_ID:$AO_KEY_SECRET" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f14e45f-ea4c-4f52-a0b1-2c9e7d3b6a10" \
-d '{
"from": "+13155550142",
"to": "+13155550188",
"body": "Anthony Oliva: your order 4471 shipped. Reply STOP to cancel.",
"campaign_id": "C7X4M2P"
}'
{
"id": "msg_01J8ZQ4X7K2M9N3P",
"status": "queued",
"direction": "outbound",
"from": "+13155550142",
"to": "+13155550188",
"segments": 1,
"encoding": "GSM-7",
"campaign_id": "C7X4M2P",
"created_at": "2026-07-27T18:02:11Z"
}
The segments field is what you are billed on. It is returned before the message leaves the platform, so you can check the cost of a template before you send it at volume.
4. Receive the delivery receipt
Delivery is asynchronous. Register a webhook to find out what happened.
curl https://api.anthonyoliva.com/v1/webhooks \
-u "$AO_KEY_ID:$AO_KEY_SECRET" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/anthonyoliva",
"events": ["message.delivered", "message.failed", "message.received", "message.opted_out"]
}'
Your endpoint will receive a signed POST:
{
"event": "message.delivered",
"occurred_at": "2026-07-27T18:02:14Z",
"data": {
"id": "msg_01J8ZQ4X7K2M9N3P",
"status": "delivered",
"carrier": "Verizon Wireless",
"segments": 1
}
}
Always verify the signature before trusting the payload. See Webhooks.
5. Handle replies and opt-outs
Inbound messages arrive as message.received. Opt-out keywords never reach that event: STOP, UNSUBSCRIBE, CANCEL, END, and QUIT are intercepted by the platform, added to your account suppression list, and delivered to you as message.opted_out for your records.
You cannot disable this, and any later attempt to message a suppressed number returns 422 recipient_opted_out. That behavior is deliberate — it is the single most common cause of carrier penalties.
Next steps
- Authentication for key scopes, rotation, and rate limits
- Send messages for the full request and response schema
- Webhooks for signature verification and retry behavior
- Errors for every error code and what to do about it