Skip to content

Guides

Message lifecycle

The states a message and a batch move through, and what you can rely on at each one.

How a message moves

Every message starts queued or scheduled and ends in exactly one terminal state. Terminal means terminal: a message that reaches one never transitions again.

SCHEDULED ─→ QUEUED ⇄ RETRY_SCHEDULED ─→ SUBMITTED ─→ SENT ─→ DELIVERED
     │          │                            │                └→ FAILED │ EXPIRED │ REJECTED
     │          │                            └──────────────────→ FAILED
     └──────────┴──→ CANCELLED
ValueMeaning
SCHEDULED
Parked until its scheduled time.
QUEUED
Waiting for the router.
RETRY_SCHEDULED
A delivery attempt failed and another is scheduled.
SUBMITTED
Handed to a provider, which has not yet returned a reference. A message stuck here is SMSend's problem, not yours.
SENT
The provider accepted it and returned a reference.
DELIVEREDTerminal
The handset confirmed receipt.
FAILEDTerminal
Delivery failed. The reason is in failed_reason.
EXPIREDTerminal
No delivery receipt arrived within 48 hours.
REJECTEDTerminal
The provider or operator refused it.
CANCELLEDTerminal
Dropped at send time, or cancelled with its batch.

Why receipts cannot go backwards

Each status carries a rank, and a delivery receipt is applied only if it strictly increases that rank. Operators occasionally deliver receipts out of order, and without this rule a late "submitted" receipt would overwrite a message that had already been confirmed delivered.

How a batch moves

A batch tracks the work as a whole. Only SETTLED means it is finished and the money is squared.

VALIDATING ─→ SCHEDULED ─→ QUEUED ─→ SENDING ─→ SETTLED
     │             └──────────┴─────────┴──→ CANCELLED
     └──→ REJECTED │ FAILED
ValueMeaning
VALIDATING
Accepted but not yet priced or paid for. Only reachable on the asynchronous path, and expires after 30 minutes.
SCHEDULED
Priced and reserved, waiting for its scheduled time.
QUEUED
Priced and reserved, waiting for the router.
SENDING
In flight.
SETTLEDTerminal
Finished, with the money squared and any refund posted.
REJECTEDTerminal
Every recipient was dropped before anything was reserved.
FAILEDTerminal
Validation itself failed.
CANCELLEDTerminal
Cancelled before or during sending, and refunded.

Reading the counts

The counts object on a batch reports how many messages have ever reached each state. The failed figure aggregates failed, expired and rejected messages, because for reconciliation purposes those are one category.

Counts are cumulative, not current

Settlement

A batch settles when every message has reached a terminal state, or when 72 hours have passed since it was due to send and some messages are still stranded. Both cases produce a BATCH_SETTLED event; the trigger field tells you which one it was.

Settlement is the only moment a refund figure exists. SMSend reserves money for the whole batch up front and refunds the difference once at the end, so no single message can tell you what it cost or what came back — which is why per-message events deliberately carry no money fields at all.