Conference Bridging
A conference room is a named audio mixer. Multiple participants join, all audio mixes together, all participants hear the mix. SignalWire conferences are the building block for warm transfers, team huddles, customer-agent-supervisor coaching sessions, and ad-hoc group calls.
Conference vs connect — when to use which
| Need | Use |
|---|---|
| Two-party call | connect (peer-to-peer through SignalWire) |
| Three or more parties | conference |
| Need mute/coach controls | conference |
| Need recording with separate tracks | conference (stereo or per-leg) |
| Just bridging two PSTN endpoints | connect (lower cost, simpler) |
Basic join
SWML:
version: 1.0.0
sections:
main:
- answer: {}
- connect:
to: conference:weekly_standup
LaML:
<Response>
<Dial>
<Conference>weekly_standup</Conference>
</Dial>
</Response>
Any caller hitting this script joins the room named weekly_standup. First participant typically hears music-on-hold until a second participant joins; configurable.
Conference verb parameters (LaML/SWML)
| Parameter | Default | Notes |
|---|---|---|
| beep | true | Play a beep when participant enters/leaves |
| muted | false | Join muted (can be unmuted via API) |
| start_conference_on_enter | false | When true, the conference starts only when this participant joins (admin pattern) |
| end_conference_on_exit | false | When true, all participants leave when this participant leaves (host pattern) |
| wait_url | (silence or default music) | URL or TTS to play while alone |
| max_participants | 250 | Hard cap |
| record | false | Record the entire conference |
| recording_status_callback | none | Webhook fires when recording completes |
| region | (closest) | Force a specific region for the mixer |
| coach | none | Participant SID to coach (whisper-only) |
| region | nearest | Force a media region for latency optimization |
Host and participant roles
The host pattern uses start_conference_on_enter and end_conference_on_exit:
<!-- Host -->
<Response>
<Dial>
<Conference startConferenceOnEnter="true" endConferenceOnExit="true">
meeting_42
</Conference>
</Dial>
</Response>
<!-- Participant -->
<Response>
<Dial>
<Conference startConferenceOnEnter="false" endConferenceOnExit="false">
meeting_42
</Conference>
</Dial>
</Response>
Participants wait on hold until the host joins. When the host leaves, everyone is disconnected.
Naming conventions
Conference rooms are global — any participant joining weekly_standup joins the same room. Two key implications:
- Names must be unique per use case — using
supportas a conference name will collide across customers. - Use deterministic, prefixed names —
cust_${customer_id}_${session_id}avoids collisions.
For ephemeral conferences (warm transfer rooms, ad-hoc bridges):
- connect:
to: conference:transfer_${call.id}
The ${call.id} is unique to the originating call, so each transfer gets its own room.
Adding participants mid-call
To bring in an additional party while a conference is in progress, place an outbound call to the new party with SWML/TwiML that joins them to the same conference name:
client.calls.create(
to="+13105553333",
from_="+12125551111",
url="https://your.api/conference-join.xml?room=cust_42_abc"
)
<Response>
<Dial>
<Conference>cust_42_abc</Conference>
</Dial>
</Response>
Mute and unmute
Via the LaML/REST API on the participant resource:
curl -X POST "https://{space}/api/laml/2010-04-01/Accounts/{project}/Conferences/{conf_sid}/Participants/{call_sid}.json" \
-u "${PROJECT}:${TOKEN}" \
-d "Muted=true"
Set Muted=false to unmute. Useful for an admin/host UI that displays the conference roster with mute toggles.
Hold
Place a single participant on hold (they hear hold music, others continue talking):
curl -X POST ".../Participants/{call_sid}.json" \
-d "Hold=true" \
-d "HoldUrl=http://twimlets.com/holdmusic"
Recording
Set record="record-from-start" on the conference:
<Conference record="record-from-start"
recordingStatusCallback="https://your.api/conf-recording">
meeting_42
</Conference>
Modes:
| Mode | Behavior |
|---|---|
| do-not-record | No recording (default) |
| record-from-start | Start when the first participant joins |
| record-from-answer | Same as record-from-start for conferences |
Recording is a single mixed file. For separate per-participant tracks, record each individual leg via Dial's record attribute and reconcile in post.
Coaching (whisper)
Coaching is when a supervisor joins a conference but only one specific participant (the agent) hears them — the customer doesn't. Useful for live training and quality assurance.
client.calls.create(
to="sip:supervisor@example.com",
from_="+12125551111",
url=f"https://your.api/coach.xml?coach={agent_call_sid}&room=cust_42_abc"
)
<Response>
<Dial>
<Conference coach="{agent_call_sid}">cust_42_abc</Conference>
</Dial>
</Response>
coach attribute set to the agent's CallSid → supervisor's audio goes only to the agent.
Barge-in
Barge-in is when a supervisor joins as a full participant (everyone hears them). No special parameter — just join the conference normally.
A common workflow is "monitor → whisper → barge":
- Supervisor joins muted (monitor only).
- Supervisor unmutes to whisper (coach attribute on agent only).
- Supervisor removes coach attribute → full barge-in.
Talk detection events
Conferences can fire a webhook when participants start or stop talking:
<Conference statusCallback="https://your.api/conf-events"
statusCallbackEvent="join leave mute hold talking">
meeting_42
</Conference>
Events delivered:
| Event | Trigger |
|---|---|
| join | Participant joined |
| leave | Participant left |
| mute | Participant muted/unmuted |
| hold | Participant placed on/off hold |
| talking | Talk-detection threshold crossed |
| start | Conference started (first participant) |
| end | Conference ended (last participant left) |
Useful for showing live conference UI ("Bob is talking now") or detecting silent participants.
Wait URL — music while alone
Default wait behavior plays SignalWire's hold music. Override for branded experience:
<Conference waitUrl="https://cdn.example.com/hold-music.mp3"
waitMethod="GET">
meeting_42
</Conference>
Or for dynamic wait audio (different music, announcements, "estimated wait time"):
<Conference waitUrl="https://your.api/wait-twiml">
meeting_42
</Conference>
Your endpoint returns TwiML with <Play> or <Say> instructions that loop.
Max participants and pricing
| Plan tier | Max participants | Pricing model | |---|---|---| | Standard | 250 | Per-participant per-minute | | Enterprise | Higher (negotiated) | Per-minute + flat conference fee |
Per-participant per-minute billing means a 30-minute conference with 5 participants = 150 billable minutes.
Region selection
Conferences are mixed in a SignalWire region. By default, the region is chosen based on the first participant. To force a region for latency optimization:
<Conference region="us2">meeting_42</Conference>
Regions: us1 (US East), us2 (US West), eu1 (Europe), eu2, au1 (Australia). Pick the region geographically closest to most participants.
REST conference resource
List active conferences:
GET /api/laml/2010-04-01/Accounts/{project}/Conferences.json?Status=in-progress
Update conference attributes mid-flight (e.g., end the conference, mute all):
POST /api/laml/2010-04-01/Accounts/{project}/Conferences/{conf_sid}.json
Status=completed
This terminates the conference and disconnects all participants.
Common patterns
Three-way call
A is on a call with B. A wants to add C. The standard pattern:
- Move A's leg into a conference: redirect A's call to SWML that joins conference
triple_${call_id}. - Move B's leg into the same conference: redirect B's call to SWML joining the same conference.
- Dial out to C, route to SWML joining the same conference.
A, B, C are all conferenced.
Customer-agent-supervisor coaching
- Customer-agent call active (peer-to-peer).
- Supervisor wants to listen → redirect the agent leg into a conference, dial out and redirect the customer leg into the same conference.
- Supervisor joins the conference with
coach=${agent_call_sid}— only the agent hears them.
Town hall
Host + 100 listeners. Host joins normally. Listeners join with muted="true" and endConferenceOnExit="false". Host's endConferenceOnExit="true" ends the meeting when the host leaves.
Common pitfalls
- Beep fatigue — default beep on every join/leave is annoying with large groups. Set
beep="false". - Host disconnect ends call for all — if host's network drops momentarily and
endConferenceOnExit="true", the entire conference dies. Consider grace periods or co-hosts. - Recording without consent — see call recording compliance. Conferences with consent-required participants need affirmative consent.
- Conference name collision — using
meetingas a name globally collides. Always namespace. - Forgetting
startConferenceOnEnter— without it, first participant hears music indefinitely.
Related patterns
- Warm transfer — typically implemented via conference
- Cold transfer
- Call recording compliance — multi-party recording rules
- Call routing strategies
References
- SignalWire LaML
<Conference>documentation - SignalWire SWML
connect: conference:syntax - RFC 4575 — SIP Event Package for Conference State