SMS API
Connect a validated Twilio sender and deliver SMS or MMS with per-recipient outcomes.
Current RelayAPI capability
| Property | RelayAPI behavior |
|---|---|
| Platform key | sms |
| Provider | Twilio Programmable Messaging |
| Connection | Account SID, Auth Token, and an owned SMS-capable default sender |
| Body | Up to 1,600 characters; Twilio may bill/deliver it as multiple segments |
| Recipients | 1–100 E.164 numbers, sent as separate Twilio messages |
| MMS | Up to 10 public media URLs per recipient |
| Scheduling | Yes, through RelayAPI |
| Native analytics endpoints | No |
RelayAPI's current SMS publisher is Twilio-only. It does not select Telnyx or another provider from account metadata.
Connect Twilio
curl -X POST https://api.relayapi.dev/v1/connect/sms \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "ws_example",
"account_sid": "your-twilio-account-sid",
"auth_token": "your-twilio-auth-token",
"from_number": "+15017122661"
}'Before storing the encrypted credential, RelayAPI verifies all three facts with Twilio:
- The Account SID and Auth Token authenticate.
- The Twilio account is active.
from_numberis an SMS-capable incoming number owned by that account.
The verified number and its reported MMS capability are stored as connection-owned metadata. That sender is authoritative for outbound requests: generic account metadata cannot replace it, and a credential already connected in another workspace cannot be moved by reconnecting it implicitly.
Send SMS
curl -X POST https://api.relayapi.dev/v1/posts \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: example-idempotency-key" \
-d '{
"content": "Order 12345 has shipped.",
"targets": ["acc_sms_example"],
"scheduled_at": "now",
"target_options": {
"sms": {
"phone_numbers": ["+14155238886"]
}
}
}'The account ID selects one exact Twilio connection. The broader sms selector
is also valid, but it expands to every authorized SMS account in the post's
workspace boundary. The connected sender is always used. Legacy
target_options.sms.from_number is accepted only as a matching identity
assertion; a different number fails with SMS_SENDER_MISMATCH before any
Twilio request.
Send MMS to several recipients
{
"content": "Your receipt is attached.",
"targets": ["acc_sms_example"],
"media": [
{"url": "https://cdn.example.com/receipt.png", "type": "image"}
],
"scheduled_at": "now",
"target_options": {
"sms": {
"phone_numbers": [
"+14155238886",
"+14155238887"
]
}
}
}RelayAPI creates one Twilio Message resource per recipient. This is not a group message. Twilio fetches every MediaUrl, so each URL must remain publicly reachable and meet Twilio/carrier requirements. MMS availability, file support, deliverability, registration, and pricing depend on the sender and destination; an account being connected does not guarantee every MMS will be accepted.
target_options.sms
| Field | Type | Required | Behavior |
|---|---|---|---|
phone_numbers | E.164 string array | Yes | 1–100 recipients; each becomes a separate provider effect |
from_number | E.164 string | No | Deprecated matching assertion only. It must equal the connector-verified sender and cannot override it. |
content | string | No | SMS-specific body override |
media | array | No | SMS-specific media override, up to 10 URLs |
The message must contain a body, at least one media URL, or both.
Delivery lifecycle
An HTTP success from Twilio normally means the message was accepted, not delivered. RelayAPI records each returned Message SID and maps provider states as follows:
| Twilio state | RelayAPI disposition |
|---|---|
accepted, scheduled, queued, sending | Pending/accepted |
sent | Sent |
delivered, read | Delivered |
failed, undelivered, canceled | Failed |
| Undocumented state | Outcome unknown |
Multi-recipient operations can be partial. RelayAPI preserves one effect per recipient; it does not report the whole post as successful when one recipient was rejected. Message SID reconciliation checks each accepted message independently.
Reuse the original RelayAPI idempotency key and exact body when retrying a request that did not cross the provider boundary. If the response is partial or outcome-unknown, reconcile the recorded SIDs instead of resending every recipient.
Credential and compliance lifecycle
- Twilio Auth Tokens do not refresh through OAuth. Reconnect after rotation or revocation.
- Reconnecting can validate a different sender. A publish-time field cannot change or persist another sender.
- You are responsible for sender registration, recipient consent, opt-out handling, quiet hours, carrier rules, and Twilio charges in the jurisdictions where you send.
- Disconnecting RelayAPI does not close the Twilio account or release its phone number.
Official Twilio references
- Programmable Messaging API and authentication
- Message resource: create and fetch status
- IncomingPhoneNumber resource
Found something wrong? Help us improve this page.