> ## 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.

# Escalate a live voice call into a video room

> Move an in-progress voice call to video: one click on the softphone creates a video room tied to the call, gives the agent a host join token, and issues a guest link for the remote party — optionally delivered by SMS.

# Escalate a live voice call into a video room

A voice call sometimes wants to be more than voice — a screen share to walk
through a proposal, a facial read on a negotiation, a whiteboard with the
customer's engineering team. Escalation to video takes the call you're on
and opens a video room for both parties, without asking the customer to hang
up and dial into anything.

This guide covers the `POST /voice/call-escalation/video` endpoint: what it
does on the softphone, the request and response contract, how the created
room is stamped back to the originating call, the optional remote-party SMS
notification, and how to clean the room up when the video session ends.

## 1. What "Move to video" does in the softphone

While a call is live on the
[Browser Softphone](/guides/voice-browser-softphone), the active-call HUD
offers a **Move to video** action. One click calls the escalation endpoint
with the live call SID, and both parties end up in the same video room: the
agent joins directly on a host token, and the remote party (the customer)
joins through a public guest link — delivered by SMS if requested, or share
by hand over the call itself.

The voice leg stays up until both sides are on video; the client hangs up
the phone leg once the remote party has joined, so there is no simultaneous
voice-and-video double media.

Escalation is a tenant-owned convenience — Orbit does not block or gate it
beyond the standard voice-write role guard (owner, admin, developer, or
agent). Whether and when to invite a customer onto video is your routing,
tone, and consent decision.

## 2. The endpoint

`POST /api/v1/voice/call-escalation/video` requires `voice:write` scope. The
only required field is the live `callSid`.

| Field               | Type    | Required           | Purpose                                                                                                          |
| ------------------- | ------- | ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `callSid`           | string  | yes                | The live call leg being elevated. Stamped on the created room.                                                   |
| `callLogId`         | string  | no                 | Call-log identifier for correlating the room back to the call.                                                   |
| `remotePartyNumber` | string  | no                 | E.164 number of the remote leg — used for room naming and as the SMS destination when notification is requested. |
| `remotePartyName`   | string  | no                 | Display name used in the generated room name.                                                                    |
| `roomName`          | string  | no                 | Override for the room name (defaults to `Call with <remote party>`).                                             |
| `notifyRemoteParty` | boolean | no                 | When true, send the guest link to `remotePartyNumber` by SMS.                                                    |
| `sipCredentialId`   | string  | yes when notifying | The extension the notification SMS is sent FROM.                                                                 |

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/call-escalation/video" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "callSid": "CA4f2c1d3e8a7b9c0d1e2f3a4b5c6d7e8f",
    "callLogId": "log_7f2a01c9d4e8",
    "remotePartyNumber": "+15559876543",
    "remotePartyName": "Jordan Weiss",
    "notifyRemoteParty": true,
    "sipCredentialId": "sip_01h2k3m4n5p6"
  }'
```

A successful call returns `201` with the room identifiers, the agent's host
join material, the guest invite, and the notification outcome:

```json theme={null}
{
  "data": {
    "call_sid": "CA4f2c1d3e8a7b9c0d1e2f3a4b5c6d7e8f",
    "room_id": "room_9kM3pQ",
    "room_sid": "RM_4a9f2c1d3d3b",
    "host": {
      "token": "eyJhbGciOiJIUzI1NiIs...",
      "ws_url": "wss://media.orbit.devotel.io",
      "identity": "user_9a1f23"
    },
    "guest": {
      "invite_token": "inv_tk_8d4f1a9c2b7e",
      "join_url": "https://orbit.devotel.io/en/join/inv_tk_8d4f1a9c2b7e",
      "expires_at": "2026-09-24T19:31:00.000Z"
    },
    "remote_party_notification": "sent"
  },
  "meta": {
    "request_id": "req_69d2c4b75e9a",
    "timestamp": "2026-09-24T15:31:00.000Z"
  }
}
```

The agent's browser connects the `host.ws_url` with `host.token` directly —
no second round-trip. A malformed body returns `400` with per-field
validation details; an unconfigured media service returns `503`.

## 3. The created room and its call-SID stamp

The room is created with these properties:

* **Name** — `roomName` if supplied, otherwise `Call with <remote party
  name or number>`.
* **Participant cap** — 8 seats by default (agent, remote party, and room
  for a supervisor or warm-transfer target), clamped down to your plan's
  video participant tier so an escalation can never exceed the plan's video
  allowance.
* **Empty timeout** — 300 seconds of inactivity ends the room.
* **Call traceability** — the originating identifiers are stamped into the
  room's `settings.escalation` block:
  `source: "voice_call_escalation"`, `call_sid`, `call_log_id`, plus the
  remote party's number and name when known. When you read the room later
  (`GET /api/v1/video/rooms/{roomId}`), that block ties the meeting back to
  the exact call it came from, so analytics and QA see one continuous
  interaction across voice and video.

The guest payload is a classic video invite: `join_url` opens the room as an
unauthenticated guest (the opaque invite token is the credential), and
`expires_at` is **4 hours** out — short, since the escalation is happening
now. There is no use cap, so a dropped or refreshed remote party can rejoin
through the same link. For the invite mechanics in general, see
[Video room access tokens](/guides/video-room-access-tokens).

## 4. Remote-party notification

`remote_party_notification` in the response is one of:

* **`sent`** — the guest link was delivered to `remotePartyNumber` by SMS.
* **`failed`** — the SMS could not be sent (the extension is missing,
  disabled, lacks outbound messaging, has no direct caller ID, or the
  sender number is no longer owned). The failure is **non-blocking** — the
  agent still has the guest link and can read it out over the call.
* **`not_requested`** — `notifyRemoteParty` was omitted or false; sharing
  the link is up to the agent.

The SMS is best-effort by design: an escalation must succeed even when
notification cannot. The message the remote party receives is a single line
with the join link:

```text theme={null}
You've been invited to continue this call over video. Join here: https://orbit.devotel.io/en/join/inv_tk_8d4f1a9c2b7e
```

The send goes through the same gated messaging pipeline every outbound SMS
surface uses; `sipCredentialId` only selects which of your extensions (and
therefore which caller ID) the message is sent from.

## 5. Resolve the room and tear it down

Read the room back when you need status:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/video/rooms/room_9kM3pQ" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

When the video conversation ends, end the room explicitly rather than
waiting out the empty timeout:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/video/rooms/room_9kM3pQ/end" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

The client hangs up the voice leg once both parties are in the room, the
agent ends the video room at the end of the meeting, and an unused room
self-cleans after its 300-second empty timeout.

## 6. Workflow example — voice call to video meeting

1. **Agent answers** an inbound call on the Browser Softphone and winds up
   talking to a customer who wants to see the product screen.
2. **Escalate.** The agent taps **Move to video** (or your own integration
   posts `callSid` + `notifyRemoteParty: true`). The response returns the
   host token and guest link.
3. **Customer joins.** The SMS lands on the customer's phone; they tap the
   join URL and enter the room as a guest. The agent joined directly on the
   host token.
4. **Voice leg ends.** Once the customer is visibly in the room, the client
   hangs up the phone leg — the conversation continues on video.
5. **Close.** At the end of the meeting the agent ends the room
   (`POST /api/v1/video/rooms/{roomId}/end`); the call record and the room
   stay linked by the `call_sid` stamp for QA and reporting.

## See also

* [Browser Softphone](/guides/voice-browser-softphone) — the in-dashboard
  calling surface the *Move to video* HUD action lives on.
* [Set up the browser softphone](/guides/voice-softphone-browser-calling) —
  full credential and client wiring for the embedded softphone.
* [Video room templates](/guides/video-room-templates) — saved room
  defaults when you want consistent escalation rooms by configuration.
* [Video room access tokens](/guides/video-room-access-tokens) — invite
  mechanics behind the guest link.
* [Outbound: live human overflow](/guides/outbound-live-human-overflow) —
  the reverse handoff (AI voice to a human agent) when escalation direction
  matters.
