Skip to main content
A voicemail mailbox captures a caller’s recording when nobody picks up: at the end of an IVR flow, on a queue’s overflow path, or as a DID’s routed destination. Each capture stores the recording, a transcript, and per-user read state — so a shared mailbox works like a triage queue, not a forwarded audio file. This guide covers the operator loop end to end: create the box, set the greeting, route calls into it, and work the messages. Base path: /api/v1/voice Authentication: Clerk session (Authorization: Bearer <token>) or API key (X-API-Key). Scope: voice:read for listings and playback; voice:write plus an owner, admin, or developer role for creating or changing a mailbox. Greetings are per-user — any authenticated user manages their own.

1. Mailbox concepts: personal vs. shared

Orbit keeps two mailbox shapes. Pick per audience, not per habit:
  • Personal mailbox — every user already has one. A captured message lands on the assigned user’s mailbox, and a queue whose overflowAction is "voicemail" captures against the assigned user when the queue falls through with no eligible agent. The per-user greeting (Section 3) plays to the caller; you never create this mailbox — it exists with the user.
  • Shared department mailbox — a box you create (for example support, sales, after-hours). It carries a roster of member user ids; when an inbound route or flow targets the box, every captured message is visible to every member and invisible to non-members. Read state is tracked per member — one person marking a message read doesn’t clear it for the rest.
Both shapes show up in the dashboard’s voice → voicemails page; the API is what you wire into provisioning flows, migration scripts, and shared-inbox automation.

2. Create a shared mailbox and route calls into it

POST /api/v1/voice/voicemail-boxes creates the box. name is a lowercase slug unique within your organization; label is the human-readable display; members is the roster of user ids subscribed to the box (max 50 — every id must belong to your organization or the call returns 422 with the offending ids listed).
cURL
The response is the created box with an id of the form vmbox_*. retention_days (1–2555, about seven years) sets how long messages in this box are kept — omit it to inherit the organization default. Update the roster, label, or retention with PUT /api/v1/voice/voicemail-boxes/{id} — supply only the fields you want to change; when members is supplied it replaces the roster rather than merging. List boxes (keyset-paginated, pass the previous page’s meta.pagination.cursor as cursor) with GET /api/v1/voice/voicemail-boxes, and remove one with DELETE /api/v1/voice/voicemail-boxes/{id}. Deleting a box does not delete messages already captured against it — they remain visible, grouped under the archived-box view in the dashboard. Wire a DID or flow to the box. In the IVR flow builder, set the destination node’s action to route into a voicemail box and pass the vmbox_* id. The same target exists for a DID’s inbound routing config — point the number’s route at the box and every unanswered call captures against it, visible to the member roster. A queue’s fallback works the same way from the queue side: set overflowAction when you create or update the queue so a queue with no eligible agents drops the caller into voicemail instead of ringing forever.

3. Set the greeting: upload or text-to-speech

Greetings are per-user. The assigned user’s greeting plays on personal capture; a box with no explicit greeting plays the tenant-default message. Manage your own greeting under /api/v1/voice/voicemail/greeting — no admin role required. Author by text-to-speech — the fastest path and the one most teams standardize on. Send the spoken text; the platform renders it to audio and stores it against your user:
cURL
text is capped at 500 characters — at normal speaking pace that is roughly 30 seconds, which is already longer than callers tolerate before the beep. voice_id and language (a BCP-47 code like en or en-US) are optional; omit them to use the tenant’s default voice. Upload a recorded file — MP3 or WAV, 2 MB maximum, as multipart form data:
cURL
Read the current greeting with GET /api/v1/voice/voicemail/greeting; the response carries the playback URL and its upload timestamp. Revert to the tenant default with DELETE /api/v1/voice/voicemail/greeting. For business-hours variation, keep the daytime flow’s greeting prompt in the IVR itself (the say/play node before the voicemail node) and treat the greeting endpoint as the after-hours and overflow default — the flow’s prompt wins whenever the flow runs, the mailbox greeting covers everything that lands without one.

4. Retrieve messages and keep the badge honest

List the newest messages first with cursor pagination:
cURL
Successful catches:
  • GET /api/v1/voice/voicemails/{id} returns the message with a signed, short-lived recording URL and the transcript. Transcripts are fenced — a caller without voicemail-read permission receives a masked transcript, not the raw text.
  • GET /api/v1/voice/voicemails/search?q=<term> runs full-text search across transcripts, so “find every message mentioning a refund” is one call.
  • PATCH /api/v1/voice/voicemails/{id}/read with { "is_read": true } toggles read state; DELETE /api/v1/voice/voicemails/{id} removes the message.
  • GET /api/v1/voice/voicemails/team is the shared-inbox view: box-captured and unclaimed messages with the caller’s own read state per message. POST /api/v1/voice/voicemails/{id}/claim with { "claim": true } assigns the message to you (or releases it with false); POST /api/v1/voice/voicemails/{id}/team-read marks your read state without touching anyone else’s.
  • POST /api/v1/voice/voicemails/{id}/forward forwards the recording to colleague user ids, or to an external email address when the org allows it — the recipient gets the audio as an attachment.
Notifications and MWI. New captures raise an in-dashboard notification, and — for users who turn it on — a voicemail-to-email delivery with the audio attached, so an after-hours mailbox can land in the on-call inbox without anybody polling. The message-waiting indicator comes from GET /api/v1/voice/mwi (snapshot) and GET /api/v1/voice/mwi/stream (server-sent events): new/old message counts per mailbox, which is what backlights the softphone’s voicemail badge and a SIP desk phone’s lamp. Pipe the SSE stream into any wallboard or desktop app that needs a live unread count. Callback-in-queue link. A message that needs a return call should not sit next to the queue it belongs to — send the caller back into it. Read the message, then enqueue a callback on the right queue (queue callbacks) so the return call enters the same SLA tracking and agent pool as a live caller. Teams that skip this step end up with voicemails triaged fast but answered slow.

5. Verify and troubleshoot

Run this checklist after wiring a new box:
  1. GET /api/v1/voice/voicemail-boxes — the box exists with the roster you expect.
  2. Call the DID off-hours (or overflow the queue by signing every agent out) and leave a 10-second message.
  3. GET /api/v1/voice/voicemails?limit=1 — the message appears with a transcript and a signed recording URL that plays.
  4. GET /api/v1/voice/mwi — the new-message count for the box is non-zero for each member.
  5. Mark it read as one member; confirm another member’s /voicemails/team still shows it unread.
Common failures:
  • 422 on create, members field called out: at least one user id is not in your organization or was deleted. The error lists the offending ids — fix the roster, not the call.
  • 409 on create: the name slug already exists in your organization. Names are unique per org; pick another slug or reuse the existing box.
  • Caller hears the default greeting after you uploaded a new one: greetings attach to the assigned user, not the box. A route into a shared box plays the tenant default unless the flow plays its own prompt first — upload the greeting as the user the flow assigns, or move the prompt into the flow.
  • TTS returns 503: text-to-speech is not configured for the tenant. Fall back to the multipart upload path.
  • 413 on upload: the greeting file exceeds 2 MB. Transcode to MP3 or trim the recording; voicemail intros past a minute lose callers anyway.
  • Plays for one member but is invisible to another: read state is per member — a teammate marking a message read never clears it for you. Conversely, a non-member never sees box messages at all; check the roster with GET /api/v1/voice/voicemail-boxes/{id}.

See also