The voicemail and MWI model
A voicemail is a captured inbound call recording filed into one mailbox. The Message-Waiting Indicator (MWI) is the per-mailbox count of unread versus read messages that a desk phone lamp or the browser softphone envelope badge renders. This page defines the whole model once — capture sources, mailbox identity, the count semantics, and the ownership of the notify path — so the recording library and extensions guides stay thin procedure surfaces. Read this before you wire a queue’s overflow to voicemail or build a client againstGET /api/v1/voice/mwi.
Voicemail capture is an inbound-record flow. Outbound MT voice and SMS
termination stay on the Devotel wholesale softswitch; nothing on this page
touches a termination path.
1. What MWI is and when it fires
MWI is the same idea every PBX has shipped for decades: a per-mailbox pair of counters — new (unread) and old (read-but-retained) messages — plus one boolean,Messages-Waiting. In the SIP world that payload is a
NOTIFY carrying an application/simple-message-summary body (RFC 3842)
for the message-summary event package; a Polycom, Yealink, Grandstream, or
Bria client subscribes to it and lights its lamp when the new count is
non-zero.
The platform derives those counters from the voicemails rows already
stored for the tenant — there is no separate MWI table and nothing to
provision per mailbox. The derivation is one grouped aggregate per tenant:
new= inbox messages withis_read = falseold= inbox messages withis_read = trueMessages-Waiting=new > 0
2. Where the MWI hooks sit
Three components share the work. Together they cover the SIP lamp and the browser badge with no duplicated state.- Voicemail capture service — persists the
voicemailsrow with its mailbox identity (assigned_user_idorbox_id, never both) and the initialis_read = false, then publishes the wake-up. The Jambonz edge dispatch (dispatch_to_voicemail_boxfor department boxes, the softphone user path for personal boxes) and the IVR/queue fallback verbs all land here. - MWI snapshot service — answers
GET /api/v1/voice/mwiwith the per-mailbox counts and builds the RFC 3842 body the voice-gateway NOTIFY worker stamps onto the SIP lamp notification. - MWI SSE stream —
GET /api/v1/voice/mwi/streampushes the snapshot on each Redis wake-up, with a 3-second safety-net tick so a missed pub/sub message still self-heals. The browser softphone never receives a SIP NOTIFY — it renders the envelope badge off this stream instead.
NOTIFY with the body the snapshot service built. Until a desk phone
subscribes, the web badge path above is the visible surface.
3. From capture to the recording library
Every captured voicemail lands in the recording library the same way every other recording does: the row carries a recording URL, a transcript when the speech pipeline completes, and the mailbox identity that makes it filterable. Two surfaces consume the same row:- the voicemail inbox view (the operator-facing list of unheard messages), and
- the recording library (the QA/review surface, where the same recording joins search and evaluation).
is_read on the row. Marking a message read or unread
updates that flag and immediately republishes the MWI counts, so the badge
an operator sees and the badge a desk phone lamp would show never disagree.
Retention (retention_days / delete_at) removes the row; the counts
recompute on the next snapshot because counters are derived, not stored.
4. Who owns the notify, and the tenant-scoped mailbox
A mailbox is either a personal box (one assigned user, keyed byassigned_user_id) or a department box (a named box such as Support or
Sales, keyed by box_id). The two are mutually exclusive per row — that is
the mailbox model, and MWI is keyed on mailbox identity, not on a SIP
credential. The gateway resolves the mailbox to a registered contact at
NOTIFY time.
Every component in the chain is tenant-scoped. Counts are computed against
the caller’s own tenant schema, and the Redis pub/sub channel is namespaced
by tenant id, so one tenant’s badge cannot leak another tenant’s counts.
That is also what tenant-owned means here: operators of a tenant read,
toggle, and clear their own voicemail; the platform never silently opens
that surface beyond the tenant. See the compliance tenant-owned
model for the general rule.
5. Supervisor badge versus extension owner
The badge is rendered from the same snapshot for everyone, but the mailbox identity decides whose view includes it:- An extension owner sees the envelope badge for their personal mailbox — it is their unread count.
- A supervisor sees the department-box badge for every box they can reach, plus the recording-library row for the same message, because the box is a shared mailbox rather than a private one.
6. Boundaries — what MWI is not
- Not a delivery-receipt generator. MWI is an inbound-record signal — the message already arrived. There is no carrier delivery receipt to synthesize, and treating it like a DLR would leak inbound-only data into outbound reporting.
- Not a CDP event. Voicemail/MWI state does not publish into the customer-data event bus, so segmentation cannot subscribe to “voicemail received.” The event model the CDP consumes lives in the CDP event model; voicemail stays a voice surface.
- The queue is the inbox-level pointer, not the mailbox. A queue’s
overflow action can hand a waiting call to voicemail (
voicemailoverflow), but the mailbox identity the capture writes is what the MWI counts follow — the queue points into the inbox; it does not become a mailbox itself. - Outbound termination is untouched. Capture is inbound; nothing here is a termination decision.