Receiving SMS and MMS
Receive incoming messages, access MMS attachments, and send automatic replies using TextGrid webhooks
Receive incoming SMS and MMS messages at your application's webhook endpoint, read message text and media, and optionally send an automatic reply.
1. Configure your receiving endpoint
Use a TextGrid phone number with the messaging capabilities you need. You can configure its callbacks when purchasing the number or update them later:
POST https://api.textgrid.com/2010-04-01/Accounts/YOUR_ACCOUNT_SID/IncomingPhoneNumbers/YOUR_PHONE_NUMBER_SID.json
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer YOUR_BASE64_ENCODED_CREDENTIALSSupply these form fields:
| Field | Example value |
|---|---|
smsUrl | https://example.com/webhooks/incoming-messages |
smsMethod | POST |
Use your own public endpoint in place of the fictitious URL. smsMethod defaults to POST and also supports GET. See Managing Phone Numbers for configuration and authentication details.
2. Verify the incoming request
Before processing a message, verify the X-TextGrid-Signature header using your account's Webhook Secret. This is separate from your API Auth Token.
For POST, capture the unchanged raw request body before parsing form fields. For GET, preserve the exact public request URL, including its encoded query string.
See Verifying Webhook Signatures for the complete algorithm and code samples.
3. Read the message fields
TextGrid sends POST callbacks as application/x-www-form-urlencoded, not JSON. If you configure GET, read the fields from query parameters instead.
Common fields include:
| Field | Description |
|---|---|
MessageSid | Message identifier. Save it to identify the message and detect duplicates. |
SmsMessageSid, SmsSid | Additional message identifier fields in the callback. |
AccountSid | Account receiving the message. |
From | Sender's phone number. |
To | Your receiving TextGrid phone number. |
Body | Message text. It can be empty for a media-only message. |
SmsStatus | received. |
NumMedia | Number of media attachments. |
NumSegments | Message segment count. |
ApiVersion | 2010-04-01. |
Query and form values arrive as text; parse count fields as integers after signature verification. Keep phone numbers and identifiers as strings. Null fields can be omitted.
An incoming-message callback is distinct from an outgoing delivery-status callback. Use separate endpoints or route the events appropriately. See Messaging Webhooks for both contracts.
4. Read MMS attachments
When media is present, the callback includes zero-based field pairs:
| Field | Description |
|---|---|
MediaUrl0 | URL for the first attachment. |
MediaContentType0 | Content type of the first attachment. |
MediaUrl1 | URL for the second attachment, when present. |
MediaContentType1 | Content type of the second attachment, when present. |
Read NumMedia, then process the matching MediaUrlN and MediaContentTypeN fields for each attachment. Do not assume an MMS contains only one attachment or that Body contains text.
The callback supplies media URLs, not inline Base64 file content. Retrieve and process media separately from the initial webhook acknowledgment so lengthy processing does not delay your response.
5. Acknowledge without replying
To acknowledge the message without sending an automatic reply, return HTTP 200 with Content-Type: application/xml and:
<?xml version="1.0" encoding="UTF-8"?>
<Response />An empty successful response also produces no automatic reply. Incoming-message acknowledgments accept HTTP 200, 201, 202, or 204; use 200 when returning TwiML content.
Save or durably queue the message before acknowledging it, then perform longer processing separately.
6. Send an automatic reply
To reply immediately, return HTTP 200 with Content-Type: application/xml and a messaging TwiML response:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>
<Body>Thanks for your message. Our team will respond shortly.</Body>
</Message>
</Response>Escape dynamic text correctly for XML, including characters such as & and <.
The reply is an outgoing message, so applicable sending eligibility and charges still apply. Returning TwiML does not confirm that the reply was delivered.
If you need to reply later, acknowledge the webhook without an automatic reply and send the message separately through the API. See Sending SMS and MMS. Avoid sending the same reply through both paths.
Handle opt-outs and subscription keywords
With standard keyword handling enabled, TextGrid processes opt-out and resubscription keywords and can send automatic confirmations. Keyword messages will still reach your incoming-message webhook. Record the recipient's preference and acknowledge the callback without returning a generic automatic reply for these messages.
TextGrid recognizes STOP, STOP!, STOPALL, UNSUBSCRIBE, END, QUIT, and QUIT! for opt-out; START and UNSTOP for resubscription; and HELP for help. Matching ignores letter case and surrounding whitespace and checks the entire message, not words within a longer sentence.
Automatic confirmation text and handling depend on account settings. If TextGrid has already sent an automatic response, it does not process your webhook's reply TwiML for that request. Do not rely on that suppression to prevent a separate API send from your application.
Handle duplicate callbacks and failures
Make message processing idempotent. Store MessageSid with the receiving account so that receiving the same message again does not repeat business actions or send another automatic reply. For an already processed message, acknowledge it without repeating the reply TwiML.
The primary incoming-message request is attempted at most twice. A retry occurs only for a transport result with status code zero, with a one-second delay. A nonzero HTTP response stops that retry loop, including an HTTP error response. Do not rely on returning HTTP 500 to trigger another primary attempt.
If delivery is unsuccessful and no automatic reply was already sent, TextGrid can invoke a configured smsFallbackUrl once. Configure smsFallbackMethod to match that endpoint. This behavior applies to incoming messages; outgoing delivery-status notifications have different delivery behavior.
The incoming-message timeout defaults to 15 seconds and can be configured. Respond promptly and do not rely on exactly-once delivery or unlimited retries.
Test your integration
Send an SMS to your TextGrid number and confirm that your endpoint verifies the signature, records the message, and returns the intended acknowledgment or reply.
Then test an MMS with media and a duplicate callback. Confirm that media fields are handled correctly and duplicate processing does not create another reply or repeat other side effects.
Updated about 4 hours ago