---
title: "Add or move a leg to a room"
method: POST
path: "/rooms/{id}/legs"
tags: ["Rooms"]
---

# Add or move a leg to a room

`POST /rooms/{id}/legs`

Add a leg to a room (auto-creates room if it doesn't exist). If the leg is already in a different room, it is atomically moved to the target room. A ringing inbound SIP leg is automatically answered before being added — in this case the response status is `adding` and the actual room join happens asynchronously, observable via `leg.joined_room`. Auto-answer failures surface as `leg.command_failed` with `command="add_to_room"`. Only the leg's primary audio stream joins by default; `streams` additionally mixes named secondary streams of the same leg into this room. A stream currently mixed elsewhere is moved here.

## Request body

- AddLegRequest
  - `leg_id` string, required — ID of the leg to add
  - `mute` boolean — If set, apply this mute state to the leg atomically before it joins the mixer (no race where un-muted audio enters the mix). Omit to leave current state untouched (useful when moving between rooms).
  - `deaf` boolean — If set, apply this deaf state to the leg atomically before it joins the mixer. Omit to leave current state untouched.
  - `accept_dtmf` boolean — If set, control whether this leg receives DTMF digits broadcast from other legs in the same room. Omit to leave current state untouched (default for new legs is true).
  - `role` string — If set, apply this routing role to the leg atomically before it joins the mixer. The room's routing matrix (see PUT /v1/rooms/{id}/routing) decides which other legs this leg hears and is heard by based on roles. Pass "" to clear the role (full mesh). Omit to leave the current role untouched.
  - `streams` AddRoomStream[] — Additional audio streams of the leg to mix into this room, each with its own routing role. Omit to add only the leg's primary stream. A stream already mixed elsewhere is moved here.
    - `stream_id` string, required — Stream identifier from GET /v1/legs/{id}/streams. The primary stream is not addressable here — it joins with the leg itself.
    - `role` string — Routing role for this stream inside the room.

## Response `200`

Leg added or moved

- StatusResponse
  - `instance_id` string — Instance identifier
  - `status` string, required

## Other responses

- `400` — Invalid JSON, leg not found, or leg not connected

## Changes

- **2026-08-04** `9b0a18aea1e2` — 1 info
  - added the new optional request property `streams`
- **2026-05-21** `98f1f6130e2c` — 1 info
  - added the new optional request property `role`
- **2026-04-15** `b84db4b78d2c` — 1 info
  - added the new optional request property `accept_dtmf`
- **2026-04-15** `14c046f7ad73` — 2 info
  - added the new optional request property `deaf`
  - added the new optional request property `mute`
- **2026-03-26** `d09c97c6ca8c` — 4 warning
  - removed the request property `accept_dtmf`
  - removed the request property `deaf`
  - removed the request property `mute`
  - removed the request property `role`

[Change history](https://skmtc.dev/voiceblender/apis/voiceblender-api/changes/rooms/:id/legs/post.md)

---

[API](https://skmtc.dev/voiceblender/apis/voiceblender-api.md) · [All operations](https://skmtc.dev/voiceblender/apis/voiceblender-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/voiceblender/voiceblender-api/revisions/89ff267f0958/schema)
