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+ plan

Overview

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.

At a glance
// 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.

sms.message_received · full profile
{
  "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.

Endpoint
POST https://sumgenius.ai/api/meta/webhook-send.php
Request
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.

Segment math
// 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.

Send to an opted-out number · HTTP 410
{
  "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:

HTTPTriggerError message
400to_phone doesn't match E.164to_phone must be in E.164 format (e.g. +15551234567).
403SMS not enabled on your account tierSMS access is not enabled for this account.
410Recipient has opted out (replied STOP)Recipient has opted out (replied STOP).
412No Twilio number provisioned for the accountSMS not provisioned for this account. Provision a Twilio number first.
422Message exceeds the GSM-7 (1,600) or UCS-2 (1,530) cap, or an unsupported action was usedmessage_text exceeds 1600 characters for SMS GSM-7 (1700 provided).
429Monthly SMS quota exceededMonthly SMS limit reached for this account.
502Twilio returned an error (network, invalid number, landline, region not enabled, etc.)SMS delivery failed: <Twilio error message>.
503SMS add-on is temporarily disabled platform-wideSMS 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.

Over-length body · HTTP 422
{
  "success": false,
  "status":  "error",
  "error":   "message_text exceeds 1600 characters for SMS GSM-7 (1700 provided)."
}