Skip to main content
A shared mailbox only pays off if the team around it has a system: who is handling each message, what has been seen and by whom, and where a return call goes. The team voicemail inbox is that system — one list every department member sees, with claim-based ownership so two people never chase the same caller, and read state tracked per teammate so nobody else’s habits pollute your unread count. This guide is the operating manual; set up the voicemail boxes themselves first. Base path: /api/v1/voice Authentication: Clerk session (Authorization: Bearer <token>) or API key (X-API-Key). Scope: voice:read for the list; voice:write plus an owner, admin, or developer role for claim and read-state changes.

1. Where the shared inbox lives

Open Voice → Voicemails → Team in the dashboard (/voice/voicemails/team). The page sits behind a role gate: owner, admin, and developer roles see it; other members land on their personal voicemail inbox instead. Grant one of those roles — the built-in role ladder is documented in Roles, teams, and permissions — before pointing anyone at the team view. A 403 here is the role, not the page. The personal inbox (/voice/voicemails) links to the team inbox and back, so operators can move between the two without re-navigating the sidebar.

2. Reading the list

Every row is one captured message with the caller number, the captured number it landed on, and the absolute timestamp pinned to your timezone. Two independent flags sit on top:
  • Owned (claimed) messages carry a Claimed by <name> badge so the queue shows who is handling the caller. The claimant name resolves from your team’s roster.
  • Your read state come from the user_read_at column — unread rows are highlighted for you, and a pithy “Unread by you” counter tracks only your progress. The legacy is_read flag is projected for older UI surfaces, but the team view keys off the per-user column.
Four stat tiles — Open, In progress, Unread by you, Total — plus four filter chips (Open, In progress, Mine, All) let you cut the queue the way a triage shift cuts it. A transcript search box searches caller numbers and transcript text over the loaded window; rows paginate 50 at a time behind a “Load more” button so a long window doesn’t bury the page. Filter over the API the same way: folder view, keyset cursor, and the per-user read field travel in one response:
cURL
Each row carries claimed_by_user_id / claimed_at (who owns it) and user_read_at (your state). Pass folder=spam or folder=inbox to scope the list; pass the previous page’s meta.pagination.cursor as cursor for the next page.

3. Claim and release: triage ownership

Claiming pins a message to one person without touching anyone else’s view. The API body is an action enum, not a boolean:
cURL
The semantics are explicit:
  • Claim an unclaimed message — assigns it to you, stamps claimed_at, and shows your name to the rest of the team.
  • Claim a message you already hold — a no-op; re-claiming is idempotent, so double-clicks and retry loops are safe.
  • Claim a message someone else holds409 CONFLICT with the current claimant’s id in the error details. Refresh and you see their badge.
  • Release ({ "action": "release" }) — drops ownership back to Open. Releasing someone else’s claim is owner- and admin-only; a developer role hits the same 409 as a claim attempt.
The claim never touches read state — taking ownership doesn’t mark the message read for you or anyone else.

4. Per-user read markers

Read state lives in a per-(message, user) row, so each teammate keeps an independent unread filter:
cURL
Send is_read: false to reopen a message for yourself — useful when a claim bounced back to Open and you want it back in your unread counter. Marking read never writes the legacy global is_read flag and never changes another member’s user_read_at; that’s what makes a five-person box workable instead of a first-to-open-wins race.

5. Workflow patterns

Claim semantics support a few operating modes; pick one and write it down. Solo operator — one person owns the box. Skip claims and just work the Open filter; claim only when someone covers for you, so the coverage hand-off shows who accepted what. Rotating on-call — each shift empties the Open chip before handoff. The incoming shift’s first move is filtering to Open: anything still there was claimed and not resolved by the outgoing shift. Hand off cleanly by releasing instead of leaving stale claims. Department box coverage — one shared mailbox, several members (up to 50 on the roster). The “Unread by you” tile is each member’s personal backlog; “Open” is the team’s. A healthy box keeps Open at zero more than it keeps any individual’s unread at zero. Claim before you call back — the etiquette that prevents double-calls: claim first, then ring the customer, then mark read. If two people phone the same customer, the message usually sat claimed-by-nobody for a while — treat a 409 as a save, not an error.

6. Wire it into the contact center

Triage is half the job; the return call is the other half. Play the message, claim it, then enqueue a callback on the right queue so the return call enters the same SLA tracking and agent pool as a live caller — the pattern in the Queue SLA callback runbook. Supervisors on owner or admin roles can force-release abandoned claims, so a stalled shift doesn’t park messages; the audit ledger records who claimed, released, and toggled read on every row for regulated-content evidence. On go-live, the CCaaS go-live checklist covers the voice cutover end to end — fold the box roster and this triage loop into that run rather than treating voicemail as an afterthought.

7. Troubleshoot

  • The shared list is empty but callers say they left messages — the route points at a vmbox_* id whose roster you’re not on, or the box itself is archived. Check the box and its roster with GET /api/v1/voice/voicemail-boxes and have an admin add you with PUT /api/v1/voice/voicemail-boxes/{id}. Non-members never see box messages.
  • 403 on the dashboard Team tab — your role is below developer. An owner or admin bumps it in Team settings.
  • 409 on claim, repeatedly — someone else holds the message and the badge tells you who. Releasing another member’s claim is owner/admin-only, by design.
  • A claim was released accidentally — re-claim it; the claim history lives in the audit ledger, and the claimant’s per-user read state survives the release, so no read progress is lost.
  • One member’s view shows everything read, another’s shows unread — working as intended. Read state is per user; the discrepancy means one person worked the queue and the other hasn’t. Cross-account anomalies (a user marked read in a different org’s data) are impossible by construction — every query is scoped to the caller’s tenant.
  • Transcript looks masked for one colleague, raw for another — transcript visibility follows the caller’s voicemail-read permission, not the claim. Members lacking read permission see a fenced preview; grant the permission rather than forwarding the text by hand.

See also