The single message-status map
Three concept pages describe the same outbound-message state machine from different angles, and until now nothing said which one to open for a given question. This page is that index. Read it as a hub: resolve a status here, then jump straight to the page that owns the answer you actually need — without reading three pages to find the one rule you came for. The four owners:
Two sibling lifecycle pages are deliberately separate: email delivery
lifecycle runs the same machine on a
different provider and adds two outcomes; delivery lifecycles other than
outbound is the ingress/egress split.
Neither replaces the outbound story above.
The glossary of state rows, with one owner each
Resolve a status you saw in a webhook payload or aGET /messages/:id
response here. Each row points at its one owning page; the first owner is
the primary, the second is the edge note.
bounced and complained are the two email-only outcomes; both live on the
email page. Everything else is the shared outbound machine.
The DAG in one table
Take event payloads and reconciles them against the platform rules. This is the transition table as a reader uses it — grouped by what dictates the next move, not alphabetically sorted. Cross-check it against the full table on the Message status transition rules page before you hard-code a merge.
Everything from any row to
deleted is also legal on operator request. Any
transition not listed, or a backward move not named under Recoverable
corrections, is ignored as a duplicate. The full per-from table with
verbatim allowed sets is on the Message status transition rules
page — treat that page as the merge contract and this table as the reader
digest.
When the same status means different things per channel
Three channel-specific flips change what a status tells you; none of them change the status itself.- Meta DM (Instagram, Messenger) has no DLR. Meta never emits a delivery receipt.
sentflips tosubmitted_no_receiptafter 5 minutes, and on an opted-in recipient that sentinel is a functional delivery signal, not genuine ambiguity. Branch onmetadata.no_dlr_channelto tell the Meta case from the SMPP case. Owner: Delivery lifecycle. - SMPP grace window. On SMS, MMS, voice, fax, and RCS, the receipt window
is 30 minutes. A row stuck
sentpast that window is promotedsubmitted_no_receipt(intermediate, not terminal). Owner: Delivery lifecycle; the late-arrival expiry rule and the carrier-correction allowance live on Message status transition rules. - Email adds a bounce outcome. A receiving mail server can reject after
acceptance, producing
bounced— an email-only arm the shared lifecycle treats as one bullet and the email page treats as the structural story. Owner: Email delivery lifecycle.
stat/err token a bind receives
for each canonical state — is its own surface on the Send-side DLR
model page.
Worked reconciliation: apply the merge to a report table
Suppose a day’s export of your own status mirror shows these rows, sorted by message id then by arrival time. Apply the merge contract in order.deleted or cancelled; (3) dedupe first — a redelivered event
must not re-apply a transition you already recorded. The full correctness
proof and a minimal JavaScript merge implementation live on the Message
status transition rules page.
See also
- Delivery lifecycle — what each status means and who advances it
- Message status transition rules — the allowed transitions, precedence, and merge contract
- Send-side DLR model — canonical vocabulary and SMPP encoders
- Email delivery lifecycle — the email-specific outcomes beside the shared machine
- Message status lifecycle reference — per-status semantics and the webhook-event map
- Operational sentinels — the settled-but- non-outcome statuses beside the DAG