Skip to main content

Inbox API

Agent inbox triage — assignment, snooze, status, notes Base path: /api/v1/inbox Endpoint count: 123

List the operators following a conversation

GET /api/v1/inbox/{conversationId}/followers
Returns the follower set with display projection (name + avatarUrl). Newest-first so the most recently subscribed operator is at the top of the sidebar drawer.
string
required

List team-only internal notes (newest first)

GET /api/v1/inbox/{conversationId}/internal-notes
string
required

List user ids currently viewing this conversation (legacy)

GET /api/v1/inbox/{conversationId}/viewers
Returns just the de-duped user-id list for backwards compatibility with older dashboards. New callers should use GET /inbox/conversations/:id/presence for the rich snapshot with names + avatars.
string
required

AI-deflection budget config + live monthly usage

GET /api/v1/inbox/ai-deflection/budget
Returns the tenant’s per-month AI-deflection cap configuration plus live usage (count of resolved_by_ai = true conversations this month) and a derived cost-savings panel comparing AI resolution cost to the tenant’s configured human-agent cost.

AI-draft feedback rollup (per-agent or per-template)

GET /api/v1/inbox/ai-drafts/feedback/aggregate
Returns count + per-action breakdown grouped by agent (using agent_user_id) or template (using template_id, NULLs excluded). Acceptance metrics are computed FE-side from the raw counts.
string (enum: agent|template)
required
string

Snapshot the state for one conversation (audit #PRESENCE-1)

GET /api/v1/inbox/conversations/{conversationId}/presence
Returns the live presence state — every operator currently viewing the conversation (with display name, avatar URL, and first-joined timestamp), plus every operator currently typing. The FE calls this once on conversation mount to seed its avatar stack + typing pill, then keeps state fresh via the inbox WS (presence.viewing / presence.left / typing.started / typing.stopped events). Both lists are de-duped by user id; two windows of the same user surface once.
string
required

AI macro suggestions for a conversation

GET /api/v1/inbox/conversations/{convId}/macro-suggestions
Returns the top-N macros from the caller’s visible macro library (team-shared + personal) ranked by an LLM against the last N turns of the conversation. Best-effort: LLM failure degrades to an empty list rather than 5xx so the composer keeps the manual palette open.
string
required
integer

List pending scheduled replies for a conversation

GET /api/v1/inbox/conversations/{convId}/scheduled-replies
Returns the still-pending scheduled replies (status=‘scheduled’) originated by the inbox composer for this conversation, ordered by scheduled_at ASC. Capped at 50 rows — exceeds the realistic composer-drawer scale (Zendesk / Front parity). The matching conversation row must exist in this tenant or 404 is returned.
string
required

Deflection ROI savings (configurable window)

GET /api/v1/inbox/deflection/savings
Returns a ROI snapshot for AI-deflected conversations over the requested window: resolved-deflection count × the tenant’s configured human-agent cost minus real LLM spend (from public.llm_cost_events filtered to the inbox channel). Distinct from /ai-deflection/budget which is current-month + uses a constant per-resolution cost estimate.

Aggregate AI deflection stats grouped by KB article (Intercom-Fin parity)

GET /api/v1/inbox/deflection/stats
Returns total / accepted / escalated / reopen-within-24h per (knowledge_base_id, document_id) plus a summary envelope. Window keyed on metadata.deflected_via_kb_at_ms (auto-deflect stamp); defaults to trailing 30 days when from/to not supplied.

List digital ACD queues

GET /api/v1/inbox/digital-queues
Returns every digital-channel ACD queue configured for the tenant. Inbound chat / email / WhatsApp / social conversations are routed through the first enabled queue whose channel matches — assigning the longest-idle skilled agent, holding on an SLA-timed waiting set, or overflowing per the queue’s policy.

Digital ACD queue live metrics (single queue)

GET /api/v1/inbox/digital-queues/{queueId}/stats
string
required

Digital ACD queue live metrics (tenant summary)

GET /api/v1/inbox/digital-queues/stats
Real-time backlog, oldest wait, SLA-breach count and available agents for every configured digital ACD queue, plus a tenant-wide rollup. Drives the supervisor wallboard’s digital-queue-depth widget. Read-only; reconciles with the routing engine’s waiting set.

Label distribution + AI confidence histogram + override rate

GET /api/v1/inbox/dispositions/stats

List all disposition taxonomies for this tenant

GET /api/v1/inbox/dispositions/taxonomies

List clustered deflection-miss knowledge gaps

GET /api/v1/inbox/knowledge-gaps
Returns deflection-miss rows from tenant_*.knowledge_gaps over the look-back window, clustered by token-overlap so recurring unanswered questions surface as one item with a miss_count. Each cluster carries a suggested topic hint for the KB-author to seed a new article.

List macro-folders for the calling user + team

GET /api/v1/inbox/macro-folders

List personal + shared agent macros

GET /api/v1/inbox/macros

Most-used macros for the calling user

GET /api/v1/inbox/macros/popular
Ranks by the caller’s own recent run count (last 30 days) plus each macro’s overall usage_count as a tiebreaker, so heavy hitters surface in the palette without drowning out the operator’s own favourites.

Translate an inbound message body on demand

GET /api/v1/inbox/messages/{id}/translate
Returns the message body translated to target (BCP-47 locale). Caches the result on messages.metadata.translations[<target>] so subsequent calls for the same locale are free. Intercom / Zendesk per-message translate-on-display parity.
string
required
string
required

List conversation routing rules

GET /api/v1/inbox/routing-rules
Returns every rule for the tenant, ordered by priority ASC (1 = first to evaluate) then created_at ASC as a stable tie-breaker.

List the calling user’s saved searches (alive only)

GET /api/v1/inbox/searches
Returns up to 100 saved searches for the calling user, ordered by most recently updated. Accounts with no saved searches yet receive an empty array with a 200 status.

Compute the SLA state (due-at, breach flags) for a conversation

GET /api/v1/inbox/sla/conversations/{conversationId}
string
required

List inbox SLA policies

GET /api/v1/inbox/sla/policies
Returns every SLA policy for the tenant. An empty array means the tenant inherits the platform default policy: 4h first response, 24h resolution, counted during business hours only.

List conversation tag definitions

GET /api/v1/inbox/tags
Returns the tenant’s curated tag vocabulary with display metadata (color, description, archived flag). Distinct from /conversations/tags/distinct which surfaces the applied tag strings — this endpoint returns the full vocabulary including unused tags pre-seeded for automation. Active tags only by default; pass ?include_archived=true to include archived tags.

Per-agent inbox team-performance rollup

GET /api/v1/inbox/team-performance/agents
Per-agent rollup of inbox ticket handling over the look-back window — ticket volume, open workload, resolved and reopened counts, mean first-response and resolution times, active handle-time, first-response and resolution SLA attainment, CSAT (average score plus response count), and first-contact-resolution rate. Owner/admin/supervisor roles see every agent; other roles see only their own tickets. The headline totals are computed over the full agent set regardless of the row limit. Read-only.
integer
Look-back window in days, applied to each ticket’s open time. Defaults to 30, capped at 90.
integer
Maximum number of agent rows returned, ordered by ticket volume. Defaults to 50, capped at 200.
integer
First-contact-resolution repeat-contact window in hours. A resolved ticket counts as first-contact-resolved when the same requester does not re-contact within this window. Defaults to 24, capped at 168 (7 days).

Team inbox SLA-attainment daily trend

GET /api/v1/inbox/team-performance/trends
Team-wide daily series over the look-back window — tickets opened and resolved, mean first-response and resolution times, active handle-time, first-response and resolution SLA attainment, CSAT, and first-contact-resolution rate per day. Owner/admin/supervisor roles see the whole team; other roles see only their own tickets. Read-only.
integer
Look-back window in days for the daily series. Defaults to 30, capped at 90.
integer
First-contact-resolution repeat-contact window in hours. Defaults to 24, capped at 168 (7 days).

List ticket custom field definitions

GET /api/v1/inbox/ticket-custom-fields

Per-article deflection success-rate

GET /api/v1/inbox/ticket-deflection/article-stats
Aggregates conversations.metadata.deflection_outcome per (knowledge_base_id, document_id, chunk_index) over the look-back window. success_rate = succeeded / (succeeded + failed_reopened)pending rows are excluded from the denominator because they haven’t matured past the 24h outcome window yet. Surfaces which KB chunks actually resolve tickets vs which ones get the customer to reply (Intercom Fin / Zendesk Answer Bot parity).

List ticket tag definitions

GET /api/v1/inbox/ticket-tags
Returns the tenant’s curated tag vocabulary. ?filter=active (default) excludes archived; ?filter=all includes archived; ?filter=archived returns only archived.

List inbox tickets for the tenant

GET /api/v1/inbox/tickets
Paginated list of tickets. Default page size 50, max 100. Filters (AND-combined): status, priority, source, agent_user_id (use __unassigned__ for NULL), contact_id, disposition, opened_after / opened_before (ISO-8601). Ordered by opened_at DESC.

Fetch a single ticket by id

GET /api/v1/inbox/tickets/{id}
Returns the ticket wire-shape for the given id, or 404 when no row exists in the active tenant scope. Replaces the legacy list-then-filter hydration pattern in the dashboard detail page (D3-CCAAS-04).
string
required

List attachments on a ticket

GET /api/v1/inbox/tickets/{id}/attachments
string
required

List comments on a ticket (CSPaaS P0 — BT-CSPAAS)

GET /api/v1/inbox/tickets/{id}/comments
Paginated list of comments / replies / internal notes on a ticket. Ordered created_at ASC (oldest first) per the Zendesk / Intercom thread-view convention. Filter by ?visibility=public (customer-visible) or internal (operator-only). 404 when the parent ticket is missing (distinct from a 200 empty list for a ticket with no comments yet).
string
required

List every edge touching this ticket

GET /api/v1/inbox/tickets/{id}/links
Returns up to 200 edges where :id appears as parent OR child, ordered created_at DESC. Use the response shape to render the ‘Related tickets’ panel in the dashboard ticket detail.
string
required

List the operators following a ticket

GET /api/v1/inbox/tickets/{ticketId}/followers
Returns the follower set with display projection (name + avatarUrl). Newest-first so the most recently subscribed operator is at the top of the sidebar drawer.
string
required

Fetch the ticket (if any) associated with a call

GET /api/v1/inbox/tickets/by-call/{callId}
Returns the ticket row whose call_id matches, or 404 if no ticket exists for this call. Powers the FE ‘View ticket’ action on the call-detail page.
string
required

Merged timeline of customer conversations + internal team channels + DMs

GET /api/v1/inbox/unified

List inbox saved views (personal + team)

GET /api/v1/inbox/views
Returns the calling user’s personal views plus every team-wide view for the tenant, ordered by position then created_at. Soft-deleted rows (deleted_at IS NOT NULL) are excluded.

Live counts for system smart folders + pinned saved views (audit #INBOX-VIEW-3)

GET /api/v1/inbox/views/counts

Resolve a saved-view share token to its filter snapshot + label

GET /api/v1/inbox/views/share/{token}
string
required

Live digital-channel team wallboard

GET /api/v1/inbox/wallboard
Real-time snapshot of the omnichannel inbox: active agents, open-conversation load, queue depth (unassigned), and SLA breached / at-risk counters. Owner/admin/supervisor see the whole team; other roles see their own load. Voice is excluded (it has its own supervisor wallboard). Read-only telemetry — initiates no outbound voice/SMS.
string
Optional comma-separated digital-channel allow-list (e.g. sms,email). When omitted every digital channel is reported. voice is always excluded. Capped at 20 entries.
integer
“Waiting too long” threshold (minutes) for the SLA at-risk early-warning bucket — conversations awaiting a first response older than this but not yet flagged by the breach scheduler. Defaults to 30.

Subscribe an operator to a conversation’s lifecycle updates

POST /api/v1/inbox/{conversationId}/followers
Zendesk CCs / Front followers / Intercom watchers parity. The follower receives an inbox_follower_update bell notification on every subsequent status or assign change, even after the conversation is transferred to a different owner. Idempotent — re-adding the same (conversation, user) is a no-op. Body user_id defaults to the caller; admins + owners may pass another operator’s id to subscribe them on the caller’s behalf.
string
required
string

Post a team-only internal note on a conversation

POST /api/v1/inbox/{conversationId}/internal-notes
Notes are stored in the tenant schema and never sent to the customer channel. Emits note.internal.created so other dashboards see the new note in real time.
string
required
string
required

AI reply-coach suggestions

POST /api/v1/inbox/{conversationId}/reply-suggestions
Returns 3 AI-generated reply variants (friendly / formal / empathetic) a human agent can pick and edit before sending. Not auto-send — the coach only suggests.
string
required
string

AI reply-coach suggestions (streaming)

POST /api/v1/inbox/{conversationId}/reply-suggestions/stream
Streams 3 AI-generated reply variants over Server-Sent Events. Same input contract as the buffered endpoint; FE renders cards as they parse instead of waiting for the full LLM response.
string
required
string

Flip the caller’s typing state on or off

POST /api/v1/inbox/{conversationId}/typing
Client sends { typing: true } on first keystroke after idle, { typing: false } on send or 3 s of inactivity. Server-side TTL of 5 s guarantees stale indicators never stick around.
string
required
boolean

Heartbeat — register the caller as viewing this conversation

POST /api/v1/inbox/{conversationId}/viewing
Clients send this every 20 s while the conversation is focused. Server TTL is 30 s; missing a heartbeat auto-expires presence. When called with ?leave=1 the handler unregisters the caller instead — this lets navigator.sendBeacon (POST-only) clean up presence on hard tab close where a real DELETE would be aborted before the request leaves the wire. Body may carry session_id so two tabs of the same user are tracked separately on the wire (audit #PRESENCE-1).
string
required
string
string
string
string

Record operator feedback on an AI-draft suggestion

POST /api/v1/inbox/ai-drafts/{conversationId}/feedback
Captures the operator’s action on an AI-draft suggestion (sent_verbatim / edited / discarded / regenerated) plus optional edits diff, template id, suggestion hash, and LLM confidence at suggestion-time. One row per interaction. Powers the AI-quality dashboard (per-agent + per-template accept-rate rollups).
string
required
string (enum: sent_verbatim|edited|discarded|regenerated)
required
string
string
number
object

AI reply-draft suggestion (CHAIN3 — CPaaS→AIaaS)

POST /api/v1/inbox/conversations/{conversationId}/ai-draft
Returns ONE suggested next-reply draft for the inbox composer, with a suggested action (send / escalate / end) and a self-reported confidence. The operator accepts, edits, or discards — the endpoint never sends on its own.
string
required
string

Record AI-draft outcome (retraining-loop telemetry)

POST /api/v1/inbox/conversations/{conversationId}/ai-draft/outcome
Persists one row in tenant ai_draft_outcomes for the inbox AI-draft retraining loop. Captures the draft snapshot, the operator’s outcome action (accepted / edited / rejected / discarded / regenerated), the sent body when known, and a character-level edit distance. Append-only — re-actioning produces a new row.
string
required
string
required
string (enum: send|escalate|end)
number
string (enum: accepted|edited|rejected|discarded|regenerated)
required
string
string

Manually set or override the disposition for a closed conversation

POST /api/v1/inbox/conversations/{conversationId}/disposition
string
required

Run a macro against a conversation

POST /api/v1/inbox/conversations/{convId}/run-macro
Executes each step of the macro sequentially against the given conversation. Returns the run-log id plus completed/total step counters; on partial failure the failed_step field reports the 1-based index of the step that threw.
string
required

Schedule a reply (or rendered macro) to send at a future time

POST /api/v1/inbox/conversations/{convId}/scheduled-replies
Wraps messagesService.sendMessage with scheduled_at so an inbox composer can author a reply now and have it dispatched at a future instant. The scheduler in apps/webhook-worker/src/scheduler-messages.ts picks up rows with status='scheduled' and scheduled_at <= NOW() once per minute. Channel defaults to the conversation’s channel. The scheduled_at must be in the future and ≤ 35 days out (platform horizon, audit-scheduled-at-horizon.ts).
string
required

Split selected messages into a new conversation

POST /api/v1/inbox/conversations/{id}/split
Move N messages from this conversation into a fresh conversation that shares the same contact. Useful when a single thread has accidentally accumulated two unrelated topics. The source conversation keeps its non-split messages; the target conversation is created fresh. All message_ids must currently belong to the source conversation — any id outside that set rejects the entire batch.
string
required
string[]
required
string
Optional human-readable summary for the new thread (stored on target.summary).

Warm-transfer a customer conversation to another employee (presence-checked)

POST /api/v1/inbox/conversations/{id}/transfer-to-employee
string
required

Bulk action across many conversations

POST /api/v1/inbox/conversations/bulk
Apply one of to up to 200 conversations. Returns per-id success/failure plus a bulk_undo_<uuid> token; pass that token to /conversations/bulk/undo within 60s to revert the side-effects.

Undo a recent bulk action

POST /api/v1/inbox/conversations/bulk/undo
Replay the inverse of a bulk action using the token returned from /conversations/bulk. Tokens expire after 60s; expired tokens return 410 Gone.

Create a digital ACD queue

POST /api/v1/inbox/digital-queues

Create a disposition taxonomy (admin/owner only)

POST /api/v1/inbox/dispositions/taxonomies

Promote a knowledge-gap cluster to a draft KB article

POST /api/v1/inbox/knowledge-gaps/{clusterId}/promote
Drafts a KB article from a clustered set of unanswered customer questions and uploads it as a draft document in the operator-selected knowledge base. Returns the draft article id so the FE can deep-link the operator into the KB editor for review and publish.
string
required

Create a macro-folder

POST /api/v1/inbox/macro-folders

Create a macro

POST /api/v1/inbox/macros

Preview a macro against a conversation (no side effects)

POST /api/v1/inbox/macros/{id}/preview
Renders every step the macro WOULD execute against the given conversation — mustache variables interpolated, per-locale bodies resolved, relative offsets (+2h / +1d) converted to ISO. Fires zero sendMessage / setConversationStatus / billing calls. Operator-facing confirmation surface before run-macro.
string
required

Translate an outbound agent draft to the customer’s preferred locale

POST /api/v1/inbox/reply/translate
Compose-time pre-send helper. Takes a draft text plus either conversationId or contactId and returns the body rendered in the contact’s preferred locale (or the explicit target override). The dashboard sends the translated text through the existing /messages endpoint — this route NEVER dispatches outbound traffic itself (invariant #45 unaffected).
string
required
string
string
string

Create a new routing rule

POST /api/v1/inbox/routing-rules

Dry-run a rule against a sample conversation

POST /api/v1/inbox/routing-rules/test
Returns the action that WOULD fire for the supplied sample without mutating any conversation. Accepts either an existing rule_id (fetched from the tenant) or an inline rule body so the builder UI can preview before saving.

Create a saved search for the calling user

POST /api/v1/inbox/searches

Create an inbox SLA policy

POST /api/v1/inbox/sla/policies

Test-send a configured SLA breach action

POST /api/v1/inbox/sla/policies/test-action
Dispatches the supplied breach action against a synthetic conversation so an operator can verify Slack/Teams webhook URLs route to the expected channel before saving the policy.

Create a conversation tag definition

POST /api/v1/inbox/tags

Archive (soft-delete) a conversation tag definition

POST /api/v1/inbox/tags/{id}/archive
Hides the tag from the chip-rail and filter dropdowns. Conversations that currently carry this tag string keep their tags array entry — the rename/archive flow is decoupled from the applied-tag edge so historical filters still resolve.
string
required

Restore an archived conversation tag definition

POST /api/v1/inbox/tags/{id}/unarchive
string
required

Create a ticket custom field definition (admin/owner)

POST /api/v1/inbox/ticket-custom-fields

Archive a ticket custom field (admin/owner)

POST /api/v1/inbox/ticket-custom-fields/{id}/archive
string
required

Restore an archived ticket custom field (admin/owner)

POST /api/v1/inbox/ticket-custom-fields/{id}/unarchive
string
required

Per-article thumbs feedback on the deflection card

POST /api/v1/inbox/ticket-deflection/article-feedback
Records a thumbs-up/down rating against a specific KB chunk (knowledge_base_id, document_id, chunk_index) so the article-stats endpoint can join thumbs counts onto the deflection-outcome aggregate. Idempotent: a second submission from the same user on the same chunk in the same conversation updates the existing row’s rating instead of inserting a duplicate (Intercom Fin / Zendesk Answer Bot parity).

Create a ticket tag definition (admin/owner)

POST /api/v1/inbox/ticket-tags

Archive a ticket tag definition (admin/owner)

POST /api/v1/inbox/ticket-tags/{id}/archive
string
required

Restore an archived ticket tag (admin/owner)

POST /api/v1/inbox/ticket-tags/{id}/unarchive
string
required

Auto-assign an unassigned ticket via capacity-aware round-robin

POST /api/v1/inbox/tickets/{id}/assign-auto
Picks one agent from the supplied user_ids pool using the same capacity-aware round-robin engine that powers inbox conversation routing (apps/api/src/lib/inbox-assignment.ts). Overloaded agents (loadScore >= OVERLOADED_THRESHOLD) are filtered out; if EVERY pool member is overloaded the picker falls back to the least-loaded agent. Capacity-snapshot failures degrade to capacity-unaware round-robin so a ticket is NEVER left unassigned because the wallboard query tripped. Pool rotation cursor lives in Redis at {devotel}:inbox:rr:<pool_id>; reuse the same pool_id across calls to keep the rotation coherent. 200 returns the updated ticket wire-shape + picker telemetry; 409 when the ticket is already assigned (manual re-assignment goes through PATCH /tickets/:id); 404 on missing ticket; 422 on validation failure.
string
required

Create a comment on a ticket (CSPaaS P0 — BT-CSPAAS)

POST /api/v1/inbox/tickets/{id}/comments
Operator-authored comment / reply / internal note. author_kind defaults to operator and visibility to public matching the helpdesk default. The operator’s user id is threaded from request.ctx.userId for the operator path; customer + system kinds leave it NULL. 201 on success, 404 on missing parent ticket, 422 on validation failure.
string
required

AI ticket deflection — match KB article + suggest answer

POST /api/v1/inbox/tickets/{id}/deflect
Runs cosine-similarity search across every active KB in the tenant and asks Anthropic to rank the best chunk against the customer’s question. Returns shouldDeflect=true when confidence exceeds the threshold (0.75). When true, the AI answer is also inserted into the conversation as the first agent response.
string
required

AI ticket deflection — customer accepted

POST /api/v1/inbox/tickets/{id}/deflect/accept
Customer clicked Yes on the deflection card. Closes the conversation as resolved_by_ai (status=resolved, metadata flag).
string
required

AI ticket deflection — customer confirmation (Yes/No solved?)

POST /api/v1/inbox/tickets/{id}/deflect/confirm
Synchronous post-deflection confirmation prompt. {resolved:true} closes the conversation as customer_confirmed; {resolved:false} auto-escalates to the human queue and stamps deflection_outcome=customer_rejected. Coexists with /deflect/accept + /deflect/escalate (kept for backward compatibility).
string
required

AI ticket deflection — customer escalated

POST /api/v1/inbox/tickets/{id}/deflect/escalate
Customer clicked No on the deflection card. Re-opens the conversation and flags it for human triage.
string
required

POST /api/v1/inbox/tickets/{id}/link
Stamps a link (symmetric, reference) or parent (asymmetric, epic→sub-ticket) edge from :id (source) to target_id. For link the controller canonical-orders the pair (smaller id wins parent slot) so dedupe is automatic. 404 on missing source/target; 422 on self-link; 422 on duplicate edge.
string
required

Merge ticket :id (source) into target_id (Zendesk parity)

POST /api/v1/inbox/tickets/{id}/merge
Closes :id as resolved, re-parents every comment onto the target ticket, and stamps a merge edge (parent=target, child=:id). Idempotent on duplicate-merge: the second call returns the existing edge as 200. 404 on missing source or target; 422 on self-merge, source-already-merged, or target-already-merged.
string
required

Reopen a resolved or wont_fix ticket

POST /api/v1/inbox/tickets/{id}/reopen
Dedicated reopen action — distinct from PATCH /tickets/:id {status: 'open'} so helpdesk analytics can track reopen rate as a first-class metric. Stamps reopened_at = NOW(), clears resolved_at, emits a dedicated audit row + the reopened follower fan-out kind. 404 on missing ticket, 409 when the ticket isn’t currently resolved / wont_fix.
string
required

Run a macro against a ticket

POST /api/v1/inbox/tickets/{id}/run-macro
Executes each step of the macro sequentially against the ticket. Returns the run-log id plus completed/total step counters; on partial failure the failed_step field reports the 1-based index of the step that threw. Steps with no ticket-side projection (schedule_follow_up, trigger_agent_handoff, set_disposition) are skipped silently (completed_steps < total_steps in that case).
string
required

Subscribe an operator to a ticket’s lifecycle updates

POST /api/v1/inbox/tickets/{ticketId}/followers
Zendesk ticket CCs / Front followers / Intercom watchers parity. The follower receives an inbox_ticket_follower_update bell notification on every subsequent status, assign, or comment change — even after the ticket is reassigned to a different agent. Idempotent — re-adding the same (ticket, user) is a no-op. Body user_id defaults to the caller; admins + owners may pass another operator’s id to subscribe them on the caller’s behalf.
string
required
string

Bulk-update tickets (assign / set_status / set_priority / set_type)

POST /api/v1/inbox/tickets/bulk
Apply one of to up to 200 tickets. Returns per-id success/failure so the dashboard can render a partial-success toast. assign accepts agent_user_id: null to un-assign. set_status accepts any INBOX_TICKET_STATUSES value, covering close (resolved/wont_fix) and reopen (open/pending) in one surface. No undo token in this first cut — reverting one ticket is a single PATCH call.

Create an inbox ticket (internal path, CHAIN1 stub)

POST /api/v1/inbox/tickets/internal
Operator-curated ticket creation. The auto-create path used by the voice-hangup chain link runs as a service-layer fire-and-forget (auto-disposition.service.ts) and does not use this endpoint. Expanded by the CSPaaS Option A epic (attachments, SLA tiers, customer-visible status).

Create a personal or team-wide saved view

POST /api/v1/inbox/views

POST /api/v1/inbox/views/{id}/share
string
required

Update the tenant’s AI-deflection budget config

PUT /api/v1/inbox/ai-deflection/budget

Replace custom field values on a ticket

PUT /api/v1/inbox/tickets/{id}/custom-fields
Authoritative-write. Each key must resolve to an active ticket_custom_field_defs row; value shape must match the def’s kind. null clears a single field’s value.
string
required

Replace tags on a ticket

PUT /api/v1/inbox/tickets/{id}/tags
Authoritative-write: caller sends the FULL desired tag array (deduplicated, ≤32 tags). Returns the updated tag list.
string
required

Edit a team-only internal note (author or admin/owner)

PATCH /api/v1/inbox/{conversationId}/internal-notes/{noteId}
Edit affordance is content-only. The author can always edit their own row; admins and owners can edit any note in the org. Mentions are recomputed from the new content + the FE’s resolved list — added mentions fire a fresh inbox_mention notification to the new recipients only (existing mentions are kept silent so a typo-fix edit doesn’t double-ping).
string
required
string
required
string
required
string[]

Update a digital ACD queue

PATCH /api/v1/inbox/digital-queues/{id}
string
required

Update a disposition taxonomy (admin/owner only)

PATCH /api/v1/inbox/dispositions/taxonomies/{taxonomyId}
string
required

Update a macro-folder

PATCH /api/v1/inbox/macro-folders/{id}
string
required

Update a macro

PATCH /api/v1/inbox/macros/{id}
string
required

Update a routing rule (name, priority, action, …)

PATCH /api/v1/inbox/routing-rules/{id}
string
required

Rename or re-filter a saved search (owner only)

PATCH /api/v1/inbox/searches/{id}
string
required

Update an inbox SLA policy

PATCH /api/v1/inbox/sla/policies/{id}
string
required

Update a conversation tag definition (rename / recolor)

PATCH /api/v1/inbox/tags/{id}
A rename (changing name) propagates to every conversation carrying the old tag string via array_replace on conversations.tags TEXT[]. Owner/admin only.
string
required

Patch a ticket custom field definition (admin/owner)

PATCH /api/v1/inbox/ticket-custom-fields/{id}
string
required

Patch a ticket tag definition (admin/owner)

PATCH /api/v1/inbox/ticket-tags/{id}
Renaming a tag DOES NOT propagate to per-ticket tags arrays automatically. Callers that need rename-propagation use a follow-up bulk-update; the saved-views tag filter continues to match on the literal string until the propagation completes.
string
required

Update an existing ticket (status / priority / assignee)

PATCH /api/v1/inbox/tickets/{id}
Patches one or more of status, priority, agent_user_id on the ticket. agent_user_id: null un-assigns. Transitions into resolved / wont_fix stamp resolved_at; transitions back out clear it. Returns the updated wire-shape. 404 on missing ticket, 422 on validation failure or empty patch.
string
required

Rename, reorder, re-filter, pin/unpin, recolour, or rescope a saved view

PATCH /api/v1/inbox/views/{id}
string
required

Unsubscribe an operator from a conversation

DELETE /api/v1/inbox/{conversationId}/followers/{userId}
Caller may always remove themselves. Admins + owners may remove any follower. Idempotent — removing a non-follower returns 200 (the desired end-state already holds).
string
required
string
required

Soft-delete an internal note (author or admin/owner)

DELETE /api/v1/inbox/{conversationId}/internal-notes/{noteId}
Replaces the row’s content with the [deleted] tombstone and stamps deleted_at. The row stays addressable for audit replay.
string
required
string
required

Unregister the caller as a viewer (tab close / route away)

DELETE /api/v1/inbox/{conversationId}/viewing
Body may carry session_id so a multi-window user only drops the tab that called DELETE; their other tabs stay marked viewing.
string
required
string

Delete a digital ACD queue

DELETE /api/v1/inbox/digital-queues/{id}
string
required

Delete a macro-folder (nested macros become unfiled)

DELETE /api/v1/inbox/macro-folders/{id}
string
required

Delete a macro

DELETE /api/v1/inbox/macros/{id}
string
required

Delete a routing rule

DELETE /api/v1/inbox/routing-rules/{id}
string
required

Cancel a pending scheduled inbox reply

DELETE /api/v1/inbox/scheduled-replies/{id}
Flips an inbox-originated scheduled message from scheduled to cancelled when scheduled_at hasn’t fired yet. 404 if the id doesn’t exist or the message is already past the scheduled gate (queued / sending / sent / failed / cancelled). No billing refund — billing is debited on the send-path AFTER the scheduler dequeues the row, so a still-scheduled message has no balance charge to refund.
string
required

Soft-delete a saved search (owner only)

DELETE /api/v1/inbox/searches/{id}
string
required

Delete an inbox SLA policy

DELETE /api/v1/inbox/sla/policies/{id}
string
required

Unsubscribe an operator from a ticket

DELETE /api/v1/inbox/tickets/{ticketId}/followers/{userId}
Caller may always remove themselves. Admins + owners may remove any follower. Idempotent — removing a non-follower returns 200 (the desired end-state already holds).
string
required
string
required

Soft-delete a saved view (sets deleted_at, keeps the row)

DELETE /api/v1/inbox/views/{id}
string
required