> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Supervisor warm takeover and coach mode for live voice calls

> Take over a live call from an agent without a cold transfer, or join it as an inaudible coach. Covers the console walkthrough, the takeovers REST API, the warm-handoff state machine, whisper grace, coach mode, and the queue-scoped supervisor permission model.

# Supervisor warm takeover and coach mode

A warm takeover moves a live call from an agent to a supervisor without dropping the caller: the customer keeps speaking, the supervisor's softphone leg becomes the active party, and the supervisor opens with a captured summary of the conversation so far. Coach mode is the lighter sibling: the supervisor joins audio-only to coach the agent, the caller never hears the supervisor, and the agent stays on the call.

Both run through the takeover surface: `POST/GET/PATCH /api/v1/voice/supervisor/takeovers`, the takeover dialog and history panel under **Voice → Monitoring**, and the inbox banner for digital handoffs.

## Takeover vs the monitoring verbs

[Live monitoring](https://docs.orbit.devotel.io/guides/supervisor-live-monitoring-voice.md) gives you listen, whisper, barge, and conference join. A takeover is different: it is a transfer of ownership, not an overlay on the call. After a takeover the agent's leg is dropped and the supervisor is the handling agent for the rest of the call, carrying the preserved conversation context.

| Situation | Use | Why |
| - | - | - |
| Check on a call without being heard | Listen | Silent monitoring; no audio exposure to either party. |
| Coach the agent while the agent keeps handling the call | Whisper (monitoring) | Short-lived coaching on a call you are watching right now. |
| Short, audible escalation both parties should hear | Barge | Transient presence; the agent remains the owner of the call. |
| Stay on as an audible third participant | Conference join | Persistent three-way, e.g. after a barge that needs a longer presence. |
| The agent should not own this call any longer | Warm takeover | Supervisor becomes the active party; the agent leg drops; context is preserved. |
| Coach a struggling agent for a while, with a record and a clean exit | Coach mode (`whisper_mode`) | Inaudible to the caller, agent leg never drops, row tracks the session until you end it. |

The rule of thumb: if the agent should keep the call, use a monitoring verb; if the agent should leave the call, take over; if the agent should keep the call but needs sustained help and an audit trail of the session, use coach mode. On the digital side, the equivalent escalation is the supervisor barge covered in [supervisor live monitoring for digital threads](https://docs.orbit.devotel.io/guides/supervisor-live-monitoring-digital.md).

Coach mode vs a monitoring whisper, in practice:

* A monitoring whisper is a moment-to-moment tool on a call you happen to be viewing; stopping it is informal and it leaves no dedicated takeover record.
* Coach mode creates a takeover row in `whisper_only` state, audits `supervisor.takeover.whisper_initiated`, keeps the session visible in the takeovers panel, and ends with an explicit cancel that also drops your leg. Choose it when the coaching session itself matters: training, a struggling agent you want to support for several minutes, or a compliance posture that needs "who coached whom and for how long" answerable.

## Console walkthrough

Open **Voice → Monitoring**. Every live call row exposes the takeover action next to the listen/whisper/barge controls.

1. You need a connected softphone session. If your supervisor leg is not connected, the console prompts you to connect first; the takeover redirects your existing leg into the call.
2. Select **Take over call** on the live call. The dialog shows the agent being replaced.
3. Pick a reason: Manual, Agent struggling, Customer escalation, Low quality score, or Training / coaching. The reason is stored on the takeover row and included in webhooks.
4. Pick the whisper grace: **Immediate (0 s)**, 5 s, 10 s, 15 s, or 30 s. During the grace you are bridged in whisper to coach the agent while the agent finishes their sentence; when the grace elapses the handoff runs and the agent leg drops. `0` skips the grace and hands off immediately. The default is 5 s.
5. Confirm. The dialog notes that the action is audit-logged and that you remain responsible for local call-recording and notification laws.

Below the active-calls grid, the **takeovers history panel** lists the tenant's takeover rows with their current state. Selecting a row opens a detail drawer that reads the takeover back and drives state advances: the drawer offers only the forward transitions the API accepts for the current state (for example `taken_over` offers `completed`), plus a separate **Cancel takeover** control available in every non-terminal state, and a notes field for a coaching note attached when you complete.

For digital threads, the receiving side sees the handoff in the inbox: a takeover banner flags the conversation, and a handoff context banner carries the preserved summary so the receiving supervisor opens with the same context the voice handoff carries.

## API walkthrough

All endpoints require owner, admin, or supervisor in the workspace (the same role gate as the monitoring verbs); the supervisor role is additionally queue-scoped, see [Who may initiate](#who-may-initiate).

### Initiate a takeover

```bash theme={null}
curl -X POST https://orbit.devotel.io/api/v1/voice/supervisor/takeovers \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "call_id": "call_8f3k2",
    "supervisor_call_sid": "sup_call_9",
    "agent_call_sid": "agent_call_4",
    "agent_being_replaced": "user_7qAgent",
    "reason": "customer_escalation",
    "whisper_grace_seconds": 5,
    "conversation_id": "conv_2210"
  }'
```

| Field | Required | Notes |
| - | - | - |
| `call_id` | yes | The live call being taken over. Must belong to your tenant; unknown ids return `404`. |
| `supervisor_call_sid` | yes | Your softphone call id; this leg is redirected into the call. |
| `agent_being_replaced` | yes | The agent user id handing the call over. |
| `agent_call_sid` | no | The agent's call id, dropped after the handoff. Required when `whisper_mode` is `true` (`422` otherwise). |
| `reason` | no | One of `manual` (default), `agent_struggling`, `customer_escalation`, `low_qm_score`, `training`. |
| `whisper_grace_seconds` | no | `0`–`30`, default `5`. `0` skips the grace phase. Ignored in coach mode. |
| `conversation_id` | no | Links the takeover to an inbox conversation. |
| `whisper_mode` | no | `true` starts coach mode instead of a takeover. Default `false`. |

With a non-zero grace the request returns immediately (HTTP 201) with the row in `whisper_phase`; a background scheduler runs the handoff when the grace deadline elapses. With `0` the handoff executes inside the request and the row comes back `taken_over`.

### Advance or cancel

```bash theme={null}
curl -X PATCH https://orbit.devotel.io/api/v1/voice/supervisor/takeovers/takeover_1a2b \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"state": "completed", "notes": "Closed the refund with a 12-month credit."}'
```

Only the supervisor who initiated the takeover may advance or cancel it (`403` otherwise). `state: "cancelled"` cancels; any other value must be a legal transition from the current state (`409` otherwise). `notes` (max 4000 characters) is stored on the row; use it for the post-call coaching note.

### List and read back

```bash theme={null}
curl "https://orbit.devotel.io/api/v1/voice/supervisor/takeovers?call_id=call_8f3k2&limit=50" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

Filters: `from` and `to` (ISO date or datetime bounds on creation time; a malformed value is ignored rather than erroring), `call_id`, `limit` (1–200, default 50), and `cursor` (opaque; pass back `next_cursor` from the previous page). The list returns each row plus the preserved conversation summary. A single row, with the full preserved context, is:

```bash theme={null}
curl https://orbit.devotel.io/api/v1/voice/supervisor/takeovers/takeover_1a2b \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

## The warm-handoff state machine

Every takeover row lives in one of these states:

| State | Meaning | What the caller hears |
| - | - | - |
| `requested` | Row created; handoff not yet running. | Nothing changes; the caller is still with the agent. |
| `whisper_phase` | Grace window running (supervisor coaches the agent inaudibly to the caller). The row carries a deadline; when it elapses, the handoff starts automatically. | The caller still hears only the agent. |
| `handoff_in_progress` | The leg swap is executing: your leg is redirected into the call, then the agent leg is dropped. | At most a brief bridge pause, then a new voice; no disconnect, no re-dial. |
| `taken_over` | You are the active party. | The caller is in conversation with you. |
| `completed` | You closed out the takeover (PATCH with notes). Terminal. | Call already in your hands; this is bookkeeping. |
| `cancelled` | Aborted or failed. Terminal. | The caller never left the agent. |

Legal forward transitions (cancel is allowed from every non-terminal state):

* `requested` → `whisper_phase`, `handoff_in_progress`, or `taken_over`
* `whisper_phase` → `handoff_in_progress` or `taken_over`
* `handoff_in_progress` → `taken_over`
* `taken_over` → `completed`

Details worth knowing:

* **Whisper-grace semantics**: during `whisper_phase` you hear both parties and speak to the agent only; the agent can use the grace to finish a thought or hand over cleanly. When the deadline elapses the scheduler advances the row, captures the conversation context (bounded to a few seconds; on timeout the handoff proceeds without it), and fires the leg swap.
* **Cancellation**: `PATCH … "state": "cancelled"` aborts from any non-terminal state. There is no automatic grace-to-handoff for coach mode rows (below); those end only by cancellation.
* **Failure**: if the leg swap fails, the row is set to `cancelled` and a `supervisor.takeover_failed` webhook fires; you can initiate a fresh takeover on the same call.
* **One open takeover per call**: a second initiate against a call with a non-terminal row returns `409` naming the open row.
* **Webhooks and events**: the lifecycle emits `supervisor.takeover_requested`, `supervisor.takeover_completed`, `supervisor.takeover_failed`, and `supervisor.takeover_cancelled`; the console refreshes live on the supervisor event stream, so the panel reflects scheduler-driven advances without polling.

## Coach mode (`whisper_mode`)

Coach mode reuses the takeover surface for audio-only coaching:

```bash theme={null}
curl -X POST https://orbit.devotel.io/api/v1/voice/supervisor/takeovers \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "call_id": "call_8f3k2",
    "supervisor_call_sid": "sup_call_9",
    "agent_call_sid": "agent_call_4",
    "agent_being_replaced": "user_7qAgent",
    "reason": "training",
    "whisper_mode": true
  }'
```

Semantics:

* **Audio-only coaching**: your audio routes to the agent leg only. The caller never hears you.
* **`agent_call_sid` is required**: the coach routing needs the agent leg; without it the request returns `422`.
* **No LLM context capture**: the conversation summary exists to brief a supervisor who is about to *replace* the agent. In coach mode the agent keeps driving, so no summary is generated.
* **No agent-leg drop, no grace deadline**: `whisper_grace_seconds` is ignored and nothing schedules a handoff. The agent stays the primary speaker for the whole session.
* **Terminal state `whisper_only`**: the row lands in `whisper_only`, which the handoff scheduler never touches. The only exit is `PATCH … "state": "cancelled"`, which also drops your coaching leg. The panel shows these rows as "Coach (whisper)".
* **Distinct audit action**: `supervisor.takeover.whisper_initiated` instead of `supervisor.takeover.initiated`, so compliance reporting can separate "supervisor coached" (no caller-audible change) from "supervisor replaced the agent" (new voice on the line). State advances and cancels audit as `supervisor.takeover.updated`.

Choose coach mode over a monitoring whisper when you want the session tracked, cancellable, and visible to the team in the takeovers panel; choose the monitoring whisper for ad-hoc, in-the-moment coaching on a call you are already viewing.

## Who may initiate

* **Owner and admin** (and platform staff) initiate takeovers on any queue in the workspace.
* **Supervisor** role is queue-scoped: a supervisor may initiate only on calls that landed in a queue they are explicitly assigned to supervise. Assignments are managed by an owner or admin in the team management UI. A supervisor with no queue assignments can take over no calls (fail-closed), and the `403` response does not reveal which queues exist or who supervises them.
* Calls without a queue (direct-dial, non-ACD) are not queue-gated for supervisors.
* This is the same role model the monitoring verbs use: if a supervisor can see a queue on the wallboard, they can take over its calls; advancing or cancelling a specific takeover is additionally limited to the supervisor who initiated it.

Expect these audit rows for a full lifecycle: `supervisor.takeover.initiated` (or `supervisor.takeover.whisper_initiated` in coach mode) on POST, and `supervisor.takeover.updated` on each PATCH advance or cancel.

## AI-agent conversations

Takeover also works on a live AI voice call: the same initiate call seizes the call from the AI agent, and the preserved context becomes your opening brief. The handoff interplays with the agent handoff flow described in [handing an AI voice call to a human](https://docs.orbit.devotel.io/guides/voice-ai-handoff-to-human.md): where that flow covers the AI-initiated or configured escalation path, takeover is the supervisor-initiated one, and the Orbit Voice Protocol reports it as `supervisor.takeover` (and `supervisor.release` when supervision ends) so agent-side integrations can react. For rollout planning, the oversight step in the [AI agent rollout pipeline](https://docs.orbit.devotel.io/guides/ai-agent-rollout-pipeline.md) covers when supervisors should listen, whisper, or take over during an agent's staged rollout; this guide is the how-to for the takeover half of that step.

## Worked example: an escalating billing call

1. A billing call turns hostile on the wallboard. You open **Voice → Monitoring** and **Listen** to confirm the agent is losing the thread.
2. On the call row, select **Take over call**, reason **Customer escalation**, whisper grace **5 s**, confirm. The panel shows the row in `whisper_phase`.
3. For five seconds you hear both parties and whisper to the agent: "I am taking this one, transfer the refund authority note." The caller hears only the agent.
4. At the deadline the row advances `handoff_in_progress` → `taken_over`; the agent leg drops and the caller continues with you, no re-dial. You open with the preserved summary the console captured.
5. After the call, open the row in the takeovers panel, advance it to `completed` with a coaching note ("De-escalated with a 12-month credit; revisit the refund-authority script"), or PATCH `state: "completed"` with `notes` via the API. The detail drawer reads back the final state, timestamps, and your note.

If halfway through step 3 you decide the agent can recover, **Cancel takeover** instead: the row goes `cancelled`, the agent keeps the call, and the caller never knew.

## Failure modes

| Symptom | Cause | What to do |
| - | - | - |
| `404` on initiate | `call_id` does not exist in your tenant (typo, ended call, or a call belonging to another tenant; responses deliberately do not distinguish). | Re-check the call id against the live call list. |
| `409` on initiate | An open takeover already exists on this call. | Read the existing row id from the error; advance or cancel it first. |
| `409 INVALID_TRANSITION` on PATCH | The target state is not a legal next state (e.g. `requested` → `completed`). | Follow the transition table above; use the panel drawer, which only offers legal targets. |
| `409 INVALID_STATE` on PATCH | The row is already `completed` or `cancelled`. | Terminal rows are immutable; initiate a fresh takeover if the call is still live. |
| `422` on initiate | `whisper_mode: true` without `agent_call_sid`. | Supply the agent's call id; coach routing needs the agent leg. |
| `403` on initiate | Supervisor role not assigned to the call's queue. | Ask an owner or admin to add the queue assignment. |
| `403` on PATCH | You did not initiate this takeover. | Only the initiating supervisor can advance or cancel a row. |
| `400` on initiate / PATCH | Unknown `reason` or unknown `state` value. | Use the enums listed in this guide. |
| `502` on initiate | The leg swap or coach redirect failed at the voice bridge. | The row is cancelled automatically; retry with a fresh initiate. |
| List returns an unfiltered page | A malformed `from`/`to` or cursor is ignored by design (the list degrades to "no filter", never an error). | Re-send with valid ISO dates; use `next_cursor` verbatim for paging. |

For the deeper diagnostic tree on leg-swap failures, missing agent legs, and interrupted handoffs, see [troubleshooting supervisor takeover failures](https://docs.orbit.devotel.io/troubleshooting/supervisor-takeover-failures.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.