Understanding SMS Delivery Statuses
Every message you send through the API carries its delivery state in two fields. This guide explains what they mean, every value you can receive, and how status updates reach your application.
Two status fields
For every message, the API returns:
- statusCode — a number for the delivery status
- status — a short text description of that status
The four statusCode values
statusCode is deliberately a four-value field — simple enough to switch on in code — while the status text carries the detail:
-1: Queued 0: Sent 1: Delivered 2: Not delivered
How statuses reach you
You can poll a message by its messageId at any time, but the usual pattern is to pass a callbackURL when sending: every status change is then POSTed to your application as a real-time delivery receipt. If your endpoint is down, we retry up to 10 times over 6 hours.
Status text reference
Each statusCode can carry these status descriptions:
| statusCode | status |
|---|---|
| -1 | Message queued |
| 0 | Awaiting result |
| 0 | Sending message…. |
| 0 | Under review |
| 1 | Delivered to carrier |
| 1 | Delivered to handset |
| 2 | Cannot route message |
| 2 | Destination mobile number blocked |
| 2 | Destination mobile opted out |
| 2 | Empty message |
| 2 | Error delivering message |
| 2 | Error with email message |
| 2 | Error with message |
| 2 | Invalid Sender ID |
| 2 | Invalid Unicode data |
| 2 | Invalid batch ID |
| 2 | Invalid delivery time |
| 2 | Invalid destination address |
| 2 | Invalid message type |
| 2 | Invalid or missing API ID |
| 2 | Invalid or missing parameters |
| 2 | Invalid protocol |
| 2 | Invalid source address |
| 2 | Invalid user data header |
| 2 | Maximum message parts exceeded |
| 2 | Message expired |
| 2 | Missing message ID |
| 2 | No batch template |
| 2 | Number delisted |
| 2 | Routing error |
| 2 | Unknown API message ID |
| 2 | Unknown client message ID |
| 2 | Unknown error |
| 2 | User cancelled message delivery |
Example: an expired message
Here the message was not delivered (statusCode = 2) because it could not be delivered within 7 days. The status field shows the reason:
{
"messageId": 1,
"datePosted": "YYYY-MM-DD hh:mm:ss",
"dateSent": "YYYY-MM-DD hh:mm:ss",
"sender": "[phone|sender name|email]",
"recipient": "recipient phone",
"message": "hello world",
"callbackURL": "callback url",
"cost": 1.00,
"batchId": 1,
"statusCode": 2,
"status": "Message expired"
}
Note: OTP verification via 160Verify uses its own separate statusCode set (3 = matched, 4 = failed, 5 = expired, 6 = used). See the 160Verify implementation guide.
Ready to build?
Sign up for a free trial — free SMS credits included — and track every delivery through our Australian SMS API.
Get a free API key API docs & Swagger sandbox