Implementing Asynchronous SMS Delivery Tracking with Twilio and Java
Learn how to implement asynchronous SMS delivery tracking using Twilio's Java SDK and status callbacks to ensure notifications actually reach your users.
30 Apr 2026, 20:11 UTC

The Challenge of SMS Delivery Visibility
When sending automated notifications via SMS, a successful API response from Twilio only confirms that the request was accepted for delivery—not that the message actually reached the recipient's handset. Relying solely on the initial HTTP 201 response leaves a blind spot regarding carrier filtering, invalid numbers, or network timeouts.
To solve this, you must implement a Status Callback. This is a webhook—a URL on your server that Twilio calls asynchronously—to provide real-time updates as the message moves from queued to sent, delivered, or failed.
Prerequisites
- A Twilio account with an active Account SID and Auth Token.
- A Twilio-purchased phone number.
- Java 8+ and a build tool like Maven or Gradle.
- A publicly accessible HTTP endpoint (for the status callback). For local development, tools like ngrok are required to tunnel Twilio's requests to your localhost.
Dependency Configuration
Add the Twilio Java Helper Library to your pom.xml:
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>
<version>9.x.x</version> <!-- Use the latest stable version -->
</dependency>
Dispatching Messages with Status Tracking
The MessageCreator class handles the dispatch. To track delivery, you must provide a setStatusCallback URL. This URL must be capable of receiving a POST request containing the message status and the specific MessageSid.
Security Note: Never hardcode your Account SID or Auth Token. Use environment variables to prevent credentials from being committed to version control.
import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
public class NotificationService {
public static void main(String[] args) {
// Load credentials from environment variables
String accountSid = System.getenv(\"TWILIO_ACCOUNT_SID\");
String authToken = System.getenv(\"TWILIO_AUTH_TOKEN\");
Twilio.init(accountSid, authToken);
Message message = Message.creator(
new PhoneNumber(\"+15550001111\"), // To: Must be E.164 format
new PhoneNumber(\"+15552223333\"), // From: Your Twilio Number
\"Your appointment is confirmed for tomorrow at 10 AM.\")
.setStatusCallback(\"https://your-domain.com/sms/status-update\")
.create();
System.out.println(\"Message queued with SID: \" + message.getSid());
}
}
Handling the Status Callback
When Twilio hits your callback endpoint, it sends a set of parameters. The most critical are MessageSid (the unique identifier for the message) and MessageStatus (the current state). Your server should log these and update your internal database to reflect the final delivery state.
| Status | Meaning | Action Required |
|---|---|---|
delivered |
The carrier confirmed delivery to the handset. | Mark as complete in DB. |
undelivered |
The carrier failed to deliver the message. | Log error; check for carrier filtering. |
failed |
Twilio could not send the message. | Check number format or account balance. |
Verification and Diagnostics
Testing Connectivity
To verify the implementation, execute these steps in order:
- Send to a Verified Number: If using a Twilio Trial account, send the message to a number you have manually verified in the Twilio Console.
- Inspect Console Logs: Navigate to Programmable Messaging > Logs > Messaging in the Twilio Console. Verify that the
Status Callbackcolumn shows a 200 OK response from your server. - Simulate Failure: Send a message to an intentionally invalid number (e.g., a number missing digits). Verify that your callback endpoint receives a
failedorundeliveredstatus.
Limitations and Risks
- Carrier Filtering: Even if Twilio reports
sent, some carriers may block messages containing specific keywords or high-volume traffic from non-registered numbers (A2P 10DLC compliance). - Webhook Latency: Status callbacks are asynchronous. There may be a delay between the actual delivery and the webhook hitting your server.
- E.164 Requirement: All numbers must follow the E.164 format (e.g.,
+ [country code] [subscriber number]). Failure to do so will result in an immediate API error.
Rollback and Recovery
Because this operation involves an external API call and a webhook, there is no "undo" for a sent message. However, if you find your callback endpoint is overwhelmed or failing:
- Disable Callbacks: Remove the
setStatusCallbackmethod from your Java code and redeploy to stop the incoming traffic to your server. - Log Analysis: Use the Twilio Console's Debugger to identify why your webhook is returning non-200 responses.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.