Message lifecycle
Every SMS submitted to Lisoloo walks the same status machine. You can
observe it via GET /status/{message_id} (polling) or via webhooks
(push). The status values are stable across releases — branch on them
in your code without worrying about renames.
States
Section titled “States”The values below come directly from the backend
ELisolooSmsStatus enum. Treat anything in the Terminal column
as a final state for that message (or per-recipient, for the
fine-grained breakdown).
| Status | Terminal? | Meaning |
|---|---|---|
pending | No | The gateway accepted the request and queued it. No carrier handoff yet. |
scheduled | No | The message is queued for a future scheduled_dates / recurring_schedule occurrence. |
processing | No | The carrier connector picked up the job and is dispatching to the SMSC. |
accepted | No | The SMSC accepted the message; operator-side processing in progress. |
enroute | No | The operator network is delivering to the handset. |
sent | No | The carrier confirmed dispatch. Awaiting handset acknowledgement. |
delivered | Yes | The handset acknowledged receipt. |
partially_delivered | Yes | Multi-segment message — some segments delivered, some did not. |
delivery_unknown | Yes | The carrier did not return a definitive receipt within the window. |
undelivered | Yes | The carrier reported the message as undelivered (handset unreachable, blocked, etc.). |
rejected | Yes | The carrier rejected the message before dispatch (typically: invalid sender ID or content). |
expired | Yes | The message validity window passed without delivery. |
failed | Yes | A processing failure inside the gateway or connector. |
unknown | — | Status could not be determined. |
none | — | Internal sentinel value; should not appear on a real message. |
delivered is the only fully successful terminal state. Everything
else in the Yes column is a non-success terminal state with
different operator-level causes.
State diagram
Section titled “State diagram” ┌──────────┐ submit ───────▶ │ pending │ └─────┬────┘ │ carrier picks up ▼ ┌────────────┐ │ processing │ └─────┬──────┘ │ SMSC accepts ▼ ┌──────────┐ │ sent │ └─────┬────┘ │ handset ACK │ timeout / NACK ▼ ▼ ┌────────────┐ ┌──────────┐ │ delivered │ │ failed │ └────────────┘ └──────────┘ terminal terminalA message can transition straight to failed from any earlier state if
something goes wrong — for example, a malformed MSISDN that the carrier
rejects before SMSC handoff jumps pending → failed without ever
passing through processing.
Multi-recipient sends
Section titled “Multi-recipient sends”A single POST /send with N recipients produces one message_id that
covers the whole batch. The status returned reflects the aggregate:
pendingwhile any recipient ispendingand none are terminal.processingwhile some are mid-flight.sentwhen all recipients have handed off.deliveredwhen every recipient isdelivered.failedwhen every recipient isfailed.- Mixed terminal states (some
delivered, somefailed) reportdeliveredif any succeeded,failedif none did.
For per-recipient breakdown, the GET /status/{message_id} response
includes a recipients[] array with the individual final state for
each number. (See the API reference for the schema.)
Webhook events
Section titled “Webhook events”Each status transition emits a webhook event to your configured
webhook_url (if set) and to any per-request callback_url. See
Webhook event types for the payload shapes.
The events are:
sms.queued— fired onpending(right afterPOST /sendreturns).sms.processing— fired onpending → processing.sms.sent— fired onprocessing → sent.sms.delivered— fired onsent → delivered.sms.failed— fired on any transition tofailed.
sms.delivered and sms.failed are terminal — no further events for
that message_id after they fire.
Timeouts
Section titled “Timeouts”The gateway holds an in-flight message for up to 24 hours waiting
for a final delivery receipt from the carrier. If none arrives by then
the status is set to failed with error_code: 1503 SMS_TIMEOUT and
no further retries are attempted.
Carrier-level retries (typically 3 attempts over 4 hours for transient failures) happen transparently before the gateway gives up. You will not see retry attempts as separate webhook events.
See also
Section titled “See also”- Check message status — polling patterns
- Webhook event types — per-event payloads
- Errors — error codes for
failedmessages