SMS
Send and receive SMS through the same API used for every other channel. This page covers only what is specific to SMS: phone-number routing, encoding and segment math, quota rules, opt-out, and the SMS error reference. Everything shared lives on the authentication, receiving webhooks, and Send API pages.
Add-on · $29/month · Requires Professional+ planOverview
Inbound texts to your provisioned number arrive as sms.message_received webhook events; outbound goes through the same Send API as DMs, routed by to_phone. The envelope, signing, retries, and API keys are identical to every other channel: see the envelope, verifying signatures, and authentication.
Channel rules
-
send_messageonly action
react, unreact, and typing_on are Meta-only and are rejected on an SMS conversation.
-
inboundfree
Never counted toward your monthly SMS quota, regardless of segments.
-
outbound1 quota unit per call
Each successful send counts as 1 toward the monthly SMS quota, no matter how many segments Twilio splits the message into.
Requirements: SMS access on your tier (Professional or Business) and a provisioned Twilio number under Settings → SMS. Without a provisioned number, the sms.message_received checkbox on the endpoint page is disabled.
To handle SMS conversations yourself with no AI reply, disable the SMS AI Assistant under Settings → SMS or use Global External Reply Mode; to keep message bodies out of stored delivery logs, see Inbound Body Purge.
// inbound event
event_type: "sms.message_received"
channel: "twilio_sms"
// outbound
action: send_message only
routing: to_phone (E.164) or conversation_id
quota: inbound free, outbound 1 per call
Inbound payload
A customer text arrives as an sms.message_received event: the standard envelope plus an SMS sub-block under message.sms. source.channel is always twilio_sms.
SMS-specific fields
-
customer.platform_user_idstring
The customer's phone number in E.164 format. Always present. customer.phone repeats it as a convenience (full payload profile only).
-
message.idstring
The Twilio MessageSid. Stable identifier; use it for deduplication.
-
message.text_rawstring
The full SMS body. Multi-segment SMS arrives concatenated: you receive the joined text, not individual segments.
-
message.sms.to_phone · from_phonestring
Your ChatGenius (Twilio) number that received the SMS, and the customer's number, both E.164.
-
message.sms.num_segmentsinteger
How many segments the inbound message used. Informational only.
-
message.sms.num_mediainteger
The media count Twilio reported. Forwarded for visibility, but MMS media URLs are not included in v1: message.attachments is always an empty array for SMS.
-
message.sms.encodingenum
GSM-7 or UCS-2, detected from the message body. See encoding & segments.
Signature verification, retries, and timestamp validation are identical to every other channel: see verifying signatures.
{
"event_id": "7f7a80c84bf17c4b5b72974c97365a77",
"event_type": "sms.message_received",
"occurred_at": "2026-04-27T23:22:10Z",
"source": {
"platform": "sms",
"channel": "twilio_sms"
},
"conversation": {
"id": 119301
},
"customer": {
"platform_user_id": "+15551234567",
"phone": "+15551234567"
},
"message": {
"id": "SMdb4342728f73bca6a83770a705e27b31",
"text_raw": "Hi, what time do you open Saturday?",
"attachments": [],
"sms": {
"to_phone": "+15559876543",
"from_phone": "+15551234567",
"num_segments": 1,
"num_media": 0,
"encoding": "GSM-7"
}
},
"meta": {
"version": "v1",
"payload_profile": "full",
"generated_at": "2026-04-27T23:22:10Z"
}
}
POST Sending SMS
Same endpoint and body as every other channel; the only SMS-specific routing field is to_phone. Shared fields (idempotency_key, response shape, generic errors) are documented on the Send API page: send_message, idempotency, response format, errors.
SMS routing & body
-
to_phonestring
Recipient phone in E.164 format (e.g. +15551234567). Required if conversation_id is not provided; the platform auto-sets to sms. Numbers are auto-normalized: spaces, dashes, parens, and a leading 1 without + are accepted. A number with no existing conversation auto-creates one (cold outbound).
-
conversation_idinteger
The conversation.id from a received SMS event. Use this or to_phone.
-
message_textstringrequired
The SMS body. Max 1,600 chars (GSM-7) or 1,530 chars (UCS-2). See encoding & segments.
-
from_phonenot accepted
The sender is always your provisioned sms_phone_number; sender selection is server-controlled to enforce A2P 10DLC compliance.
The success response follows the standard shape with platform: "sms", plus to_phone echoed back when it was sent in the request.
POST https://sumgenius.ai/api/meta/webhook-send.php
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "refill-reminder-001",
"action": "send_message",
"to_phone": "+15551234567",
"message_text": "Your prescription is ready for pickup. Reply STOP to opt out."
}'
Examples on this page use the Send API. New integrations should prefer POST /v1/messages, which accepts the same body and returns the v1 envelope.
Encoding & segments
SMS uses two encodings depending on the characters in the body. ChatGenius detects the encoding automatically and validates against the corresponding cap.
-
GSM-7160 / segment · cap 1,600
Latin alphabet, common punctuation, basic European accents. Concatenated messages drop to 153 chars per segment.
-
UCS-270 / segment · cap 1,530
Triggered by any emoji, non-Latin script (Arabic, Chinese, etc.), or smart quotes. Concatenated messages drop to 67 chars per segment.
One emoji can drop your character limit by more than half. A 160-character GSM-7 message that fit in 1 segment becomes a 70-char-per-segment UCS-2 message the moment a single emoji is added: same text, now 3 segments.
Quota counting
-
inboundfree
Never counted, regardless of segments.
-
outbound1 per call
Each successful send counts as 1 quota unit regardless of segment count. A 200-char GSM-7 message is 2 Twilio segments but 1 quota unit; a 200-char UCS-2 message is 3 segments, still 1 quota unit.
Segment count still matters for Twilio's carrier-level throughput limits: sending many long messages quickly can hit Twilio's per-second segment cap before it hits our monthly quota. Keep messages concise where possible.
// GSM-7: 160 chars = 1 segment, then 153 per segment
// UCS-2: 70 chars = 1 segment, then 67 per segment
"Your table is ready!" // GSM-7, 1 segment
"Your table is ready! 🎉" // UCS-2 now, still 1 segment
// 200-char GSM-7 body: 2 segments, 1 quota unit
// 200-char UCS-2 body: 3 segments, 1 quota unit
Opt-out (STOP / START)
SMS opt-out is handled automatically at multiple layers; you don't implement any of this.
-
Twilio carrier-level Advanced Opt-Out
When a recipient texts STOP, Twilio blocks all future outbound SMS to that number from your Messaging Service, regardless of any application-layer check.
-
ChatGenius app-level fast-fail
The opt-out is mirrored, so future API calls return 410 immediately without consuming a Twilio API call.
-
Re-subscription
If the recipient texts START, UNSTOP, or YES, both layers re-enable sending automatically.
You should still include opt-out language in your initial messages (e.g. "Reply STOP to opt out.") to comply with carrier and CASL/TCPA requirements.
{
"success": false,
"status": "error",
"error": "Recipient has opted out (replied STOP)."
}
SMS error reference
SMS errors follow the same general error response shape. The codes specific to SMS are:
| HTTP | Trigger | Error message |
|---|---|---|
| 400 | to_phone doesn't match E.164 | to_phone must be in E.164 format (e.g. +15551234567). |
| 403 | SMS not enabled on your account tier | SMS access is not enabled for this account. |
| 410 | Recipient has opted out (replied STOP) | Recipient has opted out (replied STOP). |
| 412 | No Twilio number provisioned for the account | SMS not provisioned for this account. Provision a Twilio number first. |
| 422 | Message exceeds the GSM-7 (1,600) or UCS-2 (1,530) cap, or an unsupported action was used | message_text exceeds 1600 characters for SMS GSM-7 (1700 provided). |
| 429 | Monthly SMS quota exceeded | Monthly SMS limit reached for this account. |
| 502 | Twilio returned an error (network, invalid number, landline, region not enabled, etc.) | SMS delivery failed: <Twilio error message>. |
| 503 | SMS add-on is temporarily disabled platform-wide | SMS webhook add-on is temporarily disabled. |
Permanent failures (invalid recipient, opted out, over-length) are not retried; they go straight to dead_letter. Transient failures (Twilio 5xx, 429, network errors) are retried with the same backoff schedule used for Meta deliveries.
{
"success": false,
"status": "error",
"error": "message_text exceeds 1600 characters for SMS GSM-7 (1700 provided)."
}