Tracking Twilio SMS Delivery with StatusCallback Webhooks and Long‑Message Handling
Learn how to reliably capture Twilio SMS delivery receipts, handle long messages, and recover from status failures using the Messaging API’s StatusCallback webhooks. The guide covers required parameters, concatenation rules, and practical verification steps.
18 Mar 2026, 05:13 UTC

Desired Outcome
Send an SMS from Twilio and end up with a reliable, machine‑readable delivery receipt that confirms the message reached the recipient’s handset. The receipt should include carrier‑level status, any error codes, and handle long messages that exceed the 160‑character GSM‑7 limit.
Prerequisites
- Twilio account with a verified messaging service or a dedicated Twilio phone number.
- Publicly reachable HTTPS endpoint that can receive POST requests (e.g., a Node.js Express app, AWS Lambda behind API Gateway, or a local tunnel like ngrok).
- Access to the Twilio Console or the Twilio CLI (twilio-cli) to create messages and view logs.
- Knowledge of the UTF‑16 encoding and SMS concatenation rules (up to 70 characters per segment).
- Optional: a database or in‑memory store to correlate MessageSid with MessageListSid for concatenated messages.
Focused Procedure
- Configure a StatusCallback URL
In the Twilio Console, navigate to the phone number or messaging service you’ll use. Set the
Messaging > Status Callback URLto your webhook endpoint, e.g.,https://example.com/twilio/dlr. Ensure the URL uses HTTPS and the endpoint is reachable from Twilio’s IP ranges. - Send a test message via the REST API
Execute the following curl command from a terminal that has the Twilio CLI installed and is logged in (or use the plain HTTP request with Basic Auth). Replace placeholders with your actual values.
curl -X POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json \ --data-urlencode "From=+15551234567" \ --data-urlencode "To=+15557654321" \ --data-urlencode "Body=Hello from Twilio! This is a test message." \ --data-urlencode "StatusCallback=https://example.com/twilio/dlr" \ -u {AccountSid}:{AuthToken}Capture the returned
MessageSidfrom the JSON response; you’ll need it for later verification. - Handle Long Messages
If the body exceeds 160 GSM‑7 characters, Twilio automatically switches to UTF‑16 and splits the message into 70‑character segments. Each segment is sent as a separate message with its own
MessageSidbut shares the sameMessageListSid.- To detect concatenation, look for the
MessageListSidfield in the webhook payload or the API response. - Track all segment
MessageSids in your store; they will arrive as separate POSTs to the webhook.
- To detect concatenation, look for the
- Process the StatusCallback Webhook
Set up your endpoint to parse the incoming POST. Twilio sends the following parameters:
Parameter Description MessageSid Unique ID for the segment. MessageStatus One of "queued", "sending", "sent", "delivered", "undelivered", "failed". ErrorCode Numeric error code if delivery failed; null otherwise. CarrierStatus Carrier‑specific status string (e.g., "DELIVERED", "REJECTED"). MessageListSid Identifier shared by all segments of a long message; null for single‑segment messages. From, To Phone numbers involved. Example Node.js handler (Express):
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.post('/twilio/dlr', async (req, res) => { const { MessageSid, MessageStatus, ErrorCode, CarrierStatus, MessageListSid, From, To } = req.body; // Persist to DB or log console.log(`DLR: ${MessageSid} - ${MessageStatus} (${CarrierStatus})`); // If this is a segment of a long message, aggregate status if (MessageListSid) { // Store mapping: MessageListSid -> array of segment statuses // After all segments reported "delivered", mark the whole message delivered. } // Respond 200 OK to Twilio res.sendStatus(200); }); app.listen(3000, () => console.log('DLR listener running on port 3000')); - Verify Delivery
Use the Twilio REST API to fetch the final status:
curl -X GET https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}.json \ -u {AccountSid}:{AuthToken}Check that
Statusis "delivered",ErrorCodeis null, andCarrierStatusindicates success (often "DELIVERED" or "DELIVERED TO HANDSET"). - Recover from Failures
If
MessageStatusis "undelivered" or "failed", inspectErrorCodeandCarrierStatusfor clues. Common actions:- Retry sending after a back‑off period if the error code indicates a temporary carrier issue (e.g., 30002).
- Contact the recipient or the carrier if the error code indicates a permanent problem (e.g., 30003 – number not reachable).
- Store the failure in a monitoring dashboard for alerting.
Expected Checks & Recovery Options
- DLR Payload Validity – Ensure the POST contains all required parameters. If any are missing, log the event and return a 400 response to trigger Twilio retry.
- Segment Ordering – For long messages, confirm that
MessageListSidsegments arrive in any order. Aggregate them before marking the message as delivered. - Cost Monitoring – Long messages increase chargeable segments. Use the
Segmentsfield in the API response to track how many segments were sent. - Regulatory Compliance – If Twilio receives an inbound STOP request, Twilio will automatically suppress future messages to that number. Verify that your webhook logs the
MessageStatus"undelivered" withErrorCode30001 when a STOP is received. - Rollback – No state change occurs during receipt processing. If you need to retry a failed segment, simply resend the message using the same body and
StatusCallbackURL; Twilio will treat it as a new message.
Limitations & Practical Checks
- Twilio’s free trial limits outbound SMS to a handful of numbers; upgrade for production.
- Carrier routing can introduce delays; the
CarrierStatusmay lag behindMessageStatus. - UTF‑16 segments can exceed 70 characters if the message contains Unicode emoji; test your payloads to ensure correct segmentation.
- Twilio’s API version can change; always set the
X-Twilio-Api-Versionheader to a known stable version (e.g., 2023-01-01) to avoid silent changes.
Practical Verification Checklist
- Send a test message and capture the
MessageSid. - Confirm the webhook receives the POST with
MessageStatus=deliveredandErrorCode=null. - Cross‑check via the REST API:
Status=delivered,CarrierStatus=DELIVERED. - For long messages, validate that multiple
MessageSids share the sameMessageListSidand that all segments report delivered. - Simulate an undelivered scenario (e.g., send to a number that is unreachable) and observe the error code in the webhook.
By following this guide, you’ll have a robust, end‑to‑end pipeline for verifying Twilio SMS delivery, handling concatenated messages, and recovering gracefully from carrier‑level failures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.