diff --git a/fern/apis/signalwire-rest/openapi.yaml b/fern/apis/signalwire-rest/openapi.yaml
index 4bcaf767e4..a09c2c4d96 100644
--- a/fern/apis/signalwire-rest/openapi.yaml
+++ b/fern/apis/signalwire-rest/openapi.yaml
@@ -42396,9 +42396,8 @@ components:
coach:
type: string
description: |-
- Joins the conference in coaching mode for the participant identified by the given call SID.
- The coach hears the whole conference, but is heard only by the coached participant; the other participants cannot hear the coach.
- The call SID must belong to a call that is currently connected to the in-progress conference. Specifying a call SID that does not exist or is no longer connected will result in a failure.
+ Joins the conference as a coach for the participant identified by the given call ID (a UUID). The coach hears the whole conference but is heard only by the coached participant; the other participants cannot hear the coach.
+ The call ID must belong to a participant currently in the in-progress conference, or the join fails. A muted coach is heard by nobody.
examples:
- b3877ee3-6f3c-4985-8066-6d24e3f65e12
status_callback_event:
diff --git a/fern/products/compatibility-api/pages/cxml/voice/conference-noun.mdx b/fern/products/compatibility-api/pages/cxml/voice/conference-noun.mdx
index 36cc19badd..bdf336c35a 100644
--- a/fern/products/compatibility-api/pages/cxml/voice/conference-noun.mdx
+++ b/fern/products/compatibility-api/pages/cxml/voice/conference-noun.mdx
@@ -79,7 +79,7 @@ puts response.to_s
- Coach accepts a call [SID](/docs/platform/what-is-a-sid) of a call that is currently connected to an in-progress conference. Specifying a call SID that does not exist or is no longer connected to the conference will result in the call failing to the action URL and throwing a 13240 error.
+ The call [SID](/docs/platform/what-is-a-sid) of a participant already in the conference to coach. This call becomes the coach: only the coached participant hears it, and its audio stays out of the main conference mix. If the SID is not a current participant, the join fails and `` completes with a `DialCallStatus` of `busy`. A muted coach is heard by nobody. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring) for listen-in, whisper, and barge workflows.
@@ -539,10 +539,12 @@ end
puts response.to_s
```
-Participants who enter a conference call muted can hear the other participants in the call who are unmuted. However, the unmuted participants cannot hear the muted callers. Muting and unmuting can be enabled and disabled in real-time via a REST API.
+Participants who enter a conference call muted can hear the other participants in the call who are unmuted. However, the unmuted participants cannot hear the muted callers. Muting and unmuting can be enabled and disabled in real-time via a REST API. For a supervisor workflow that moves between silent monitoring, coaching, and speaking, see [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
### Coaching a conference call
+The `coach` attribute makes the joining call a coach for the participant whose call SID it names. The coach hears the whole conference, and only the coached participant hears the coach. Everyone else, including a customer on the line, hears nothing from the coach. The coached participant must already be in the conference, and a coach who is also muted is heard by nobody.
+
```xml
@@ -577,7 +579,7 @@ class Example
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference("Example-Room",
- coach: 'AgentCallSid');
+ coach: "AgentCallSid");
response.Append(dial);
Console.WriteLine(response.ToString());;
@@ -601,7 +603,7 @@ require 'signalwire/sdk'
response = Signalwire::Sdk::VoiceResponse.new do |response|
response.dial do |dial|
- dial.conference('Example-Room', coach: '')
+ dial.conference('Example-Room', coach: 'AgentCallSid')
end
end
diff --git a/fern/products/platform/pages/calling/voice/overview.mdx b/fern/products/platform/pages/calling/voice/overview.mdx
index 939b6c8cc2..a4dfc41a20 100644
--- a/fern/products/platform/pages/calling/voice/overview.mdx
+++ b/fern/products/platform/pages/calling/voice/overview.mdx
@@ -84,6 +84,9 @@ SignalWire's advanced APIs and elastic cloud infrastructure make it a breeze to
Capture a whole call, a single message, or a conference, then manage the files.
+
+ Listen in on, whisper to, or barge an agent's call from a supervisor console.
+
{/* Core links */}
diff --git a/fern/products/platform/pages/calling/voice/supervisor-call-monitoring.mdx b/fern/products/platform/pages/calling/voice/supervisor-call-monitoring.mdx
new file mode 100644
index 0000000000..5572d890c8
--- /dev/null
+++ b/fern/products/platform/pages/calling/voice/supervisor-call-monitoring.mdx
@@ -0,0 +1,259 @@
+---
+title: Supervisor call monitoring
+slug: /voice/supervisor-call-monitoring
+description: Listen in on a live call silently, whisper to an agent without the customer hearing, or barge in, using SignalWire conferences from SWML, cXML, REST, or the Server SDKs.
+max-toc-depth: 3
+---
+
+[join-conference]: /docs/swml/reference/calling/join-conference
+[conference-noun]: /docs/compatibility-api/cxml/reference/voice/conference
+[update-participant]: /docs/compatibility-api/rest/conference-participants/update-participant
+[list-participants]: /docs/compatibility-api/rest/conference-participants/list-all-participants
+[call-commands]: /docs/apis/rest/calls/call-commands
+[create-a-call]: /docs/compatibility-api/rest/calls/create-a-call
+[sdk-py-dial]: /docs/server-sdks/reference/python/rest/calling/dial
+[sdk-ts-dial]: /docs/server-sdks/reference/typescript/rest/calling/dial
+[sid]: /docs/platform/what-is-a-sid
+[call-whisper]: /docs/swml/guides/call-whisper
+[ai-params]: /docs/swml/reference/calling/ai/params
+[ai-sidecar]: /docs/swml/reference/calling/ai-sidecar
+[stream]: /docs/swml/reference/calling/stream
+[tap]: /docs/swml/reference/calling/tap
+
+A supervisor on a contact-center floor needs three things from a live call: to hear it without being heard, to coach the agent without the customer hearing, and to step into the conversation outright. SignalWire supports all three on any call that runs inside a conference, and a supervisor console can move between them mid-call with one REST request per switch.
+
+Monitoring works on conference participants only. The agent's call must already be in a SignalWire conference before a supervisor can hear it, so route agent calls through [`join_conference`][join-conference] in SWML or [``][conference-noun] in cXML rather than a plain two-party connect. There is no way to listen to, whisper into, or barge a call that is bridged directly to another call.
+
+## The three modes
+
+Two participant settings drive every mode: `muted` and `coach`. There is no separate listen-in or barge parameter to look for.
+
+| Mode | Supervisor hears | Supervisor is heard by | Settings on the supervisor's call |
+|---|---|---|---|
+| Listen in | Everyone | Nobody | `muted` on |
+| Whisper | Everyone | The agent only | `muted` off, `coach` set to the agent's call ID |
+| Barge | Everyone | Everyone | `muted` off, no `coach` |
+
+The `coach` setting names the participant being coached. The call that carries it becomes the coach: its audio goes to the coached participant alone and stays out of the main conference mix, so the customer never hears it. A muted coach is not heard by anyone, so whisper requires the supervisor to be unmuted.
+
+## Before you start
+
+You need three values, all of them from the agent's side of the call:
+
+- **The conference name** the agent's call joined.
+- **The agent's call ID.** Read it from the conference `join` status callback, or from [List all active Participants][list-participants]. cXML and the Compatibility REST API call this value the call SID; SWML and the Calling API call it the call ID. Each is the [UUID that identifies the call][sid].
+- **The conference SID**, from the same status callback or from the participants list. The REST requests below address the supervisor by conference SID and call ID.
+
+REST requests use a project API token with the Voice scope.
+
+There is no REST request that adds a participant to a conference. To bring a supervisor in, create a call whose instructions join the conference, with [Send call commands][call-commands] on the Calling API for SWML or [Create a call][create-a-call] on the Compatibility API for cXML, or let the supervisor dial a number that runs those instructions.
+
+## Listen in
+
+Join the supervisor's call to the agent's conference with `muted` on. The supervisor hears every unmuted participant and is heard by nobody.
+
+```yaml title="SWML"
+version: 1.0.0
+sections:
+ main:
+ - join_conference:
+ name: support-floor
+ muted: true
+```
+
+Silent monitoring leaves no marker of its own. A muted supervisor looks like any other muted participant in the participant list and in status callbacks, so if you need a record of who listened to which call, write it in your application from the `join` and `leave` events.
+
+## Whisper
+
+Join unmuted and set `coach` to the agent's call ID. The supervisor hears the whole conference, and only the agent hears the supervisor.
+
+```yaml title="SWML"
+version: 1.0.0
+sections:
+ main:
+ - join_conference:
+ name: support-floor
+ coach: b3877ee3-6f3c-4985-8066-6d24e3f65e12
+```
+
+The agent must be in the conference when the supervisor joins. If the call ID in `coach` is not a current participant, the join fails: in cXML, `` completes with a `DialCallStatus` of `busy` and control passes to its action URL; in SWML, `join_conference_result` reports the failure and the script continues.
+
+## Barge
+
+Join unmuted with no `coach`, and the supervisor is an ordinary participant that everyone hears. In practice a supervisor rarely joins this way. They start by listening or whispering and barge by changing state, as the next section shows.
+
+## Switch modes during the call
+
+Markup sets a participant's state at join time. Changing it afterward is a cross-call operation, so it belongs to the REST API rather than to the supervisor's own SWML or cXML: [Update a Participant][update-participant] on the Compatibility REST API changes `Muted`, `Coaching`, and `CallSidToCoach` for any participant, whether the conference was joined from SWML or cXML. A supervisor console with three buttons makes one request per press.
+
+| From | To | Request body |
+|---|---|---|
+| Listen in | Whisper | `Muted=false` `Coaching=true` `CallSidToCoach=` |
+| Listen in | Barge | `Muted=false` |
+| Whisper | Barge | `Coaching=false` |
+| Whisper | Listen in | `Muted=true` `Coaching=false` |
+| Barge | Whisper | `Coaching=true` `CallSidToCoach=` |
+| Barge | Listen in | `Muted=true` |
+
+The request is form-encoded, addressed by the conference SID and the supervisor's call ID:
+
+```bash title="Listen in to whisper"
+curl -X POST "https://example.signalwire.com/api/laml/2010-04-01/Accounts/$PROJECT_ID/Conferences/$CONFERENCE_SID/Participants/$SUPERVISOR_CALL_ID" \
+ -u "$PROJECT_ID:$API_TOKEN" \
+ --data-urlencode "Muted=false" \
+ --data-urlencode "Coaching=true" \
+ --data-urlencode "CallSidToCoach=$AGENT_CALL_ID"
+```
+
+The only reader this split inconveniences is a supervisor dialing in from a handset with no application behind them. Give that supervisor a console, or a separate number whose instructions join in each mode.
+
+### End to end with the Server SDKs
+
+The Server SDKs place the supervisor's call: [`dial`][sdk-py-dial] on the Calling API accepts inline SWML, so the supervisor leg joins the conference muted without a hosted document. The SDKs have no client for the Compatibility REST API, so the mode switch is one form-encoded HTTP request authenticated with the project ID and API token. The agent's call ID and the conference SID come from the conference's `join` status callback.
+
+
+```python title="Python" {15-22,36,39}
+import requests
+from signalwire.rest import RestClient
+
+PROJECT_ID = "your-project-id"
+API_TOKEN = "your-api-token"
+SPACE = "your-space.signalwire.com"
+
+client = RestClient(project=PROJECT_ID, token=API_TOKEN, host=SPACE)
+
+# Both values arrive on the conference's `join` status callback for the agent's call.
+conference_sid = "e2a5f5c3-0b6d-4d7f-9c2a-1f3b4c5d6e7f"
+agent_call_id = "b3877ee3-6f3c-4985-8066-6d24e3f65e12"
+
+# 1. Bring the supervisor in silently.
+supervisor = client.calling.dial(
+ from_="+15551234567",
+ to="+15559876543",
+ swml={
+ "version": "1.0.0",
+ "sections": {"main": [{"join_conference": {"name": "support-floor", "muted": True}}]},
+ },
+)
+supervisor_call_id = supervisor["id"]
+
+participant_url = (
+ f"https://{SPACE}/api/laml/2010-04-01/Accounts/{PROJECT_ID}"
+ f"/Conferences/{conference_sid}/Participants/{supervisor_call_id}"
+)
+
+def set_mode(**fields):
+ response = requests.post(participant_url, auth=(PROJECT_ID, API_TOKEN), data=fields)
+ response.raise_for_status()
+ return response.json()
+
+# 2. Whisper: unmute and coach the agent in one request.
+set_mode(Muted="false", Coaching="true", CallSidToCoach=agent_call_id)
+
+# 3. Barge: stop coaching, and everyone hears the supervisor.
+set_mode(Coaching="false")
+```
+
+```typescript title="TypeScript" {15-22,43,46}
+// Install: npm install @signalwire/sdk@2.0.5
+import { RestClient } from "@signalwire/sdk";
+
+const PROJECT_ID = "your-project-id";
+const API_TOKEN = "your-api-token";
+const SPACE = "your-space.signalwire.com";
+
+const client = new RestClient({ project: PROJECT_ID, token: API_TOKEN, host: SPACE });
+
+// Both values arrive on the conference's `join` status callback for the agent's call.
+const conferenceSid = "e2a5f5c3-0b6d-4d7f-9c2a-1f3b4c5d6e7f";
+const agentCallId = "b3877ee3-6f3c-4985-8066-6d24e3f65e12";
+
+// 1. Bring the supervisor in silently.
+const supervisor = await client.calling.dial({
+ from: "+15551234567",
+ to: "+15559876543",
+ swml: {
+ version: "1.0.0",
+ sections: { main: [{ join_conference: { name: "support-floor", muted: true } }] },
+ },
+});
+const supervisorCallId = supervisor.id;
+
+const participantUrl =
+ `https://${SPACE}/api/laml/2010-04-01/Accounts/${PROJECT_ID}` +
+ `/Conferences/${conferenceSid}/Participants/${supervisorCallId}`;
+
+async function setMode(fields: Record) {
+ const response = await fetch(participantUrl, {
+ method: "POST",
+ headers: {
+ Authorization: "Basic " + Buffer.from(`${PROJECT_ID}:${API_TOKEN}`).toString("base64"),
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: new URLSearchParams(fields),
+ });
+ if (!response.ok) throw new Error(`Participant update failed: ${response.status}`);
+ return response.json();
+}
+
+// 2. Whisper: unmute and coach the agent in one request.
+await setMode({ Muted: "false", Coaching: "true", CallSidToCoach: agentCallId });
+
+// 3. Barge: stop coaching, and everyone hears the supervisor.
+await setMode({ Coaching: "false" });
+```
+
+
+
+The TypeScript sample pins `@signalwire/sdk@2.0.5`, whose `dial()` takes a single options object. The [TypeScript `dial` reference][sdk-ts-dial] documents the positional `dial(from, to, options)` form of a newer release. Match the form to the version you install.
+
+
+To confirm the switch took effect, retrieve the supervisor's participant record. `coaching` is `true` and `call_sid_to_coach` holds the agent's call ID while whispering, and `muted` is `true` while listening in. If the update returns error 16002, `Coaching` was `true` without a `CallSidToCoach`, or the call ID in `CallSidToCoach` is not in that conference.
+
+## Keep the console in sync
+
+Subscribe to participant events so the console's buttons reflect state set anywhere, including a mute from another tool. In SWML, set `status_callback` and `status_callback_event` on the `join_conference` that creates the conference; in cXML, set `statusCallback` and `statusCallbackEvent` on ``. The `join`, `leave`, `mute`, `hold`, and `speaker` events carry each participant's mute state and coaching state: `muted` and `coaching` in SWML callbacks, `Muted`, `Coaching`, and `CallSidToCoach` in cXML callbacks.
+
+## Limits
+
+- **Conference only.** A directly bridged two-party call cannot be monitored. Put agent calls in a conference from the start if supervisors may need to join.
+- **The agent must be present first.** A `coach` that names a call outside the conference fails the join, and a REST update naming one returns error 16002.
+- **A participant cannot coach itself.**
+- **Muted wins.** A muted coach is heard by nobody. Whisper needs `Muted=false` alongside `Coaching=true`.
+- **The coach leaves with the agent.** When the coached participant leaves the conference, every participant coaching them is removed from it too, and each of those calls continues with whatever follows the join in its own instructions. Switch a supervisor to listen in or barge before the agent hangs up if they need to stay.
+- **Several supervisors can coach one agent** at the same time. Each coach whispers to one participant.
+- **Same project.** A supervisor can only join conferences in the project that created them.
+
+## Recording and consent
+
+
+Listening to, coaching on, or joining a call counts as monitoring or recording under laws that vary by country, by state, and by whether the call is inbound or outbound. Many require notice to one or both parties. SignalWire plays no notice and performs no consent check for you. Your application is responsible for any announcement, consent capture, and record-keeping the law requires. Consult qualified counsel before deploying supervisor monitoring.
+
+
+Coaching state is visible: the participant record and the participant status callbacks report `coaching` and the coached call ID. Silent monitoring is not distinguished from any other muted participant, so keep your own log if you need one.
+
+## Not the same as
+
+Several features share this vocabulary and do something else:
+
+- **[Call whisper][call-whisper]** in SWML plays an announcement to the person answering before the caller is connected. It is call screening, not coaching.
+- **AI barge** in [`ai.params`][ai-params] controls whether a caller can interrupt the AI agent's speech. It has nothing to do with a human joining a call.
+- **[`ai_sidecar`][ai-sidecar]** observes a call and emits text for a UI. It injects no audio and is not a participant.
+- **[`stream`][stream] and [`tap`][tap]** fork call audio to a WebSocket or RTP endpoint. The receiver gets a media stream, not a call leg, and cannot speak into the call.
+
+## Next steps
+
+
+
+ Every SWML conference parameter, including `muted`, `coach`, and the status callback events.
+
+
+ The `` attributes and the status callback fields.
+
+
+ The REST request that switches a participant between modes.
+
+
+ Place the supervisor's call with inline SWML from Python, with a TypeScript twin.
+
+
diff --git a/fern/products/platform/pages/getting-started.mdx b/fern/products/platform/pages/getting-started.mdx
index 35277d93f9..ae731548e9 100644
--- a/fern/products/platform/pages/getting-started.mdx
+++ b/fern/products/platform/pages/getting-started.mdx
@@ -149,9 +149,10 @@ This is common for:
**If you need straightforward call handling** (IVRs, call forwarding, playing messages), use **[SWML](/docs/swml)**.
Your server responds to webhooks with JSON/YAML instructions. It's stateless and works with any programming language.
-**If you need realtime control** (live call monitoring, mid-call transfers, complex orchestration), use the **[RELAY client](/docs/server-sdks/guides/relay-client)**.
+**If you need realtime control** (reacting to call events as they happen, mid-call transfers, complex orchestration), use the **[RELAY client](/docs/server-sdks/guides/relay-client)**.
It maintains a persistent WebSocket connection for instant, bi-directional communication.
Best for applications that need to react to events as they happen.
+For a supervisor who listens in on, whispers to, or barges an agent's call, see [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
**If you're building AI voice agents**, use the **[Server SDKs](/docs/server-sdks)**.
They're designed for creating conversational AI that handles phone calls, in the language of your choice:
diff --git a/fern/products/server-sdks/pages/reference/python/agents/function-result/join-conference.mdx b/fern/products/server-sdks/pages/reference/python/agents/function-result/join-conference.mdx
index a3c1252cac..6bd10e76b6 100644
--- a/fern/products/server-sdks/pages/reference/python/agents/function-result/join-conference.mdx
+++ b/fern/products/server-sdks/pages/reference/python/agents/function-result/join-conference.mdx
@@ -74,8 +74,9 @@ used internally. Passing any non-default parameter triggers the full object form
- SWML Call ID or CXML CallSid of a participant who can coach (whisper to)
- this participant without other participants hearing.
+ Call ID of the participant to coach. The call that sets this becomes the
+ coach: only the coached participant hears it, and its audio stays out of the
+ main conference mix. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
diff --git a/fern/products/server-sdks/pages/reference/python/relay/call/join-conference.mdx b/fern/products/server-sdks/pages/reference/python/relay/call/join-conference.mdx
index 8e12da6ba9..93f0cd9b5e 100644
--- a/fern/products/server-sdks/pages/reference/python/relay/call/join-conference.mdx
+++ b/fern/products/server-sdks/pages/reference/python/relay/call/join-conference.mdx
@@ -72,7 +72,9 @@ This method emits [`calling.conference`][calling-conference] events. See [Call E
- Call ID of a participant who can hear but not be heard (coaching mode).
+ Call ID of the participant to coach. The call that sets this becomes the
+ coach: only the coached participant hears it, and its audio stays out of the
+ main conference mix. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
diff --git a/fern/products/server-sdks/pages/reference/typescript/agents/function-result/join-conference.mdx b/fern/products/server-sdks/pages/reference/typescript/agents/function-result/join-conference.mdx
index a053aa2381..ae73ab345b 100644
--- a/fern/products/server-sdks/pages/reference/typescript/agents/function-result/join-conference.mdx
+++ b/fern/products/server-sdks/pages/reference/typescript/agents/function-result/join-conference.mdx
@@ -75,8 +75,9 @@ used internally. Passing any non-default parameter triggers the full object form
- SWML Call ID or CXML CallSid of a participant who can coach (whisper to)
- this participant without other participants hearing.
+ Call ID of the participant to coach. The call that sets this becomes the
+ coach: only the coached participant hears it, and its audio stays out of the
+ main conference mix. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
diff --git a/fern/products/server-sdks/pages/reference/typescript/relay/call/join-conference.mdx b/fern/products/server-sdks/pages/reference/typescript/relay/call/join-conference.mdx
index dec6da01c0..95717ac6bc 100644
--- a/fern/products/server-sdks/pages/reference/typescript/relay/call/join-conference.mdx
+++ b/fern/products/server-sdks/pages/reference/typescript/relay/call/join-conference.mdx
@@ -70,7 +70,9 @@ This method emits [`calling.conference`][calling-conference] events. See [Call E
- Call ID of a participant who can hear but not be heard (coaching mode).
+ Call ID of the participant to coach. The call that sets this becomes the
+ coach: only the coached participant hears it, and its audio stays out of the
+ main conference mix. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
diff --git a/fern/products/swml/pages/guides/recipes/call-whisper.mdx b/fern/products/swml/pages/guides/recipes/call-whisper.mdx
index 545d7b9d3e..9257434109 100644
--- a/fern/products/swml/pages/guides/recipes/call-whisper.mdx
+++ b/fern/products/swml/pages/guides/recipes/call-whisper.mdx
@@ -15,6 +15,10 @@ Call Whisper is a feature that allows you to play a message to the recipient of
This feature is useful for informing the recipient about the nature of the call before they answer it.
This guide shows you how to perform a Call Whisper using SWML to inform the recipient the number of the caller.
+
+Looking for a supervisor who whispers to an agent during a live call? That is conference coaching, covered in [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring).
+
+
## Setting up the SWML scripts
To perform a Call Whisper using SWML, you need to create two
diff --git a/fern/products/swml/pages/reference/methods/calling/join_conference.mdx b/fern/products/swml/pages/reference/methods/calling/join_conference.mdx
index 940acee8ea..a8ba3c70a6 100644
--- a/fern/products/swml/pages/reference/methods/calling/join_conference.mdx
+++ b/fern/products/swml/pages/reference/methods/calling/join_conference.mdx
@@ -75,9 +75,9 @@ This method allows you to connect the current call to a named conference where m
- Joins the conference in coaching mode for the participant identified by the given [call SID](/docs/platform/what-is-a-sid). The coach hears the whole conference, but is heard only by the coached participant -- the other participants cannot hear the coach. Use this to whisper guidance to an agent while they are on a live call.
+ Joins the conference as a coach for the participant identified by the given [call ID](/docs/platform/what-is-a-sid) (a UUID). The coach hears the whole conference but is heard only by the coached participant; the other participants cannot hear the coach. Use this to whisper guidance to an agent on a live call.
- The call SID must belong to a call that is currently connected to the in-progress conference. Specifying a call SID that does not exist or is no longer connected will result in a failure.
+ The call ID must belong to a participant currently in the in-progress conference, or the join fails. A muted coach is heard by nobody. See [Supervisor call monitoring](/docs/platform/voice/supervisor-call-monitoring) for listen-in, whisper, and barge workflows.
diff --git a/specs/swml/calling/Methods/join_conference/main.tsp b/specs/swml/calling/Methods/join_conference/main.tsp
index 3d1e9c3ce3..ce2af33de5 100644
--- a/specs/swml/calling/Methods/join_conference/main.tsp
+++ b/specs/swml/calling/Methods/join_conference/main.tsp
@@ -88,9 +88,8 @@ model JoinConferenceObject {
trim?: "trim-silence" | "do-not-trim" = "trim-silence";
@doc("""
- Joins the conference in coaching mode for the participant identified by the given call SID.
- The coach hears the whole conference, but is heard only by the coached participant; the other participants cannot hear the coach.
- The call SID must belong to a call that is currently connected to the in-progress conference. Specifying a call SID that does not exist or is no longer connected will result in a failure.
+ Joins the conference as a coach for the participant identified by the given call ID (a UUID). The coach hears the whole conference but is heard only by the coached participant; the other participants cannot hear the coach.
+ The call ID must belong to a participant currently in the in-progress conference, or the join fails. A muted coach is heard by nobody.
""")
@example("b3877ee3-6f3c-4985-8066-6d24e3f65e12")
coach?: string;
diff --git a/specs/swml/calling/tsp-output/@typespec/json-schema/SWMLObject.json b/specs/swml/calling/tsp-output/@typespec/json-schema/SWMLObject.json
index d173afa947..74362d006a 100644
--- a/specs/swml/calling/tsp-output/@typespec/json-schema/SWMLObject.json
+++ b/specs/swml/calling/tsp-output/@typespec/json-schema/SWMLObject.json
@@ -4257,7 +4257,7 @@
"examples": [
"b3877ee3-6f3c-4985-8066-6d24e3f65e12"
],
- "description": "Joins the conference in coaching mode for the participant identified by the given call SID.\nThe coach hears the whole conference, but is heard only by the coached participant; the other participants cannot hear the coach.\nThe call SID must belong to a call that is currently connected to the in-progress conference. Specifying a call SID that does not exist or is no longer connected will result in a failure."
+ "description": "Joins the conference as a coach for the participant identified by the given call ID (a UUID). The coach hears the whole conference but is heard only by the coached participant; the other participants cannot hear the coach.\nThe call ID must belong to a participant currently in the in-progress conference, or the join fails. A muted coach is heard by nobody."
},
"status_callback_event": {
"type": "string",