> For complete lifecycle-event payload schemas and examples, use the canonical overview: Session /api/sessions; Room lifecycle, participants, and room playback /api/rooms; Session playback /api/playback; Recording /api/recording; DTMF /api/keypad-input; Messages /api/messages; WebSocket Session /api/web-socket. Use /api/event-delivery for transport behavior. Endpoint pages name relevant events, but these overviews are the canonical references.

# Set room participant audience

POST https://api.vorbal.dev/v1/sessions/{uuid}/room/audience
Content-Type: application/json

**Rate limit: Per command** · **Burst:** 15 · **Refill:** 10 req/s

Set who hears a [room participant](/api/room-participants). The request body is an
audience object selected by `type`:

* `everyone`: everyone in the room hears the participant.
* `nobody`: nobody in the room hears the participant.
* `participants`: only the room participants listed in `participants` hear the participant.

**Triggered webhooks:** `room.participant.audience_changed` (deferred, emitted only when the participant's effective audience changes), `room.participant.audience_change_failed`

With `participants`, the listed participants still hear the room normally, and the participant keeps
hearing the whole room. Nobody else in the room hears the participant, and neither does the room
recording. A session recording of a listed participant includes the participant. For example:

```json
{"type": "participants", "participants": [{"uuid": "<session uuid of a listed participant>", "volume": 5}]}
```

Each listed participant has an optional `volume`, an integer from 1 to 9 (default `5`, normal/unchanged,
the same scale as `POST /v1/sessions/{uuid}/room/volume`). It sets how loudly that participant hears this
participant's whisper, and nothing else: how the listed participant hears the room, how the room hears
them, and their own `room/volume` setting are unchanged. To change one participant's volume, send the
audience again with the new value; the other listed participants keep their volume, and the whisper
continues without interruption.

A `participants` request returns `400` with `code: invalid_request` when the list is empty, repeats a
`uuid`, contains the participant itself, has a `volume` outside 1 to 9, or lists more sessions than the room's
participant limit.

A listed session that is not a current participant of the same room is not an error: a participant can
leave between reading the participant list and sending the request, so that session is dropped from
the list and the request is still accepted.

When a listed participant leaves the room, it is removed from the list. An empty list means nobody
hears the participant; the audience never reverts to `everyone`. Changing the audience to `everyone`
or `nobody` stops the listed participants from hearing the participant privately.

The `202` response acknowledges asynchronous admission. The change is complete when one of these webhooks arrives:

* `room.participant.audience_changed` after the whole requested audience is in effect, only when the effective audience changes. Its `audience`
  is the effective new audience, including `participants` without any dropped session.
* `room.participant.audience_change_failed` with `reason: execution_failed` when the requested audience
  could not be put fully in effect, including a `volume` that could not be applied. `failed_participants`
  lists the session UUIDs of the participants that do not hear the participant, and `audience` is the
  audience actually in effect.

After a `participants` audience is in effect, `room.participant.audience_change_failed` with
`reason: audience_lost` reports a listed participant that stopped hearing the participant. A failure
never makes the participant audible to the whole room.

Requests are applied in the order they are accepted, so the last accepted request determines the final
audience. Requesting the audience the participant already has returns `202` and emits no event.

See [Room lifecycle, participant, and playback events](/api/rooms#lifecycle-participant-and-playback-events) for complete payload schemas and examples.

Reference: https://docs.vorbal.dev/api/room-participants/audience

## Authentication

- `Authorization` header (bearer token, required) — Send `Authorization: Bearer <app_uuid>:<api_key>` using an active API key. See [Authentication](https://voice-platform.docs.buildwithfern.com/api/authentication) for details.

## Request

### Path parameters

- `uuid` (string, required) — [Session](/api/sessions) identifier.

### Headers

- `Idempotency-Key` (string, optional) — Optional key for safely retrying mutating requests. An explicitly empty header is treated like omission and does not enable replay protection. See [Idempotency](https://voice-platform.docs.buildwithfern.com/idempotency) for details.

### Body (application/json)

This endpoint expects a RoomAudience.

- `RoomAudience`
  - `type`: `everyone` (everyone)
  - `type`: `nobody` (nobody)
  - `type`: `participants` (participants)
    - `participants` (list of RoomAudienceParticipantsParticipantsItems, required) — The participants who hear this participant, each with the volume at which they hear it. A request must list at least one participant, without a repeated `uuid`, without the participant itself, and no more than the room's participant limit. A listed participant that is not a current participant of the same room is dropped from the list instead of failing the request. Responses and webhooks show the effective list, which is empty after every listed participant left or was dropped.

## Response

### 202

Participant audience change in progress

- `room_id` (string, required)
- `status` (enum, required)
  - Allowed values: `in_progress`

## Errors

### 400 Bad Request Error

Missing `Authorization` or malformed Bearer credentials return `invalid_authorization_header`; invalid request parameters return `invalid_request`. A syntactically valid credential with an invalid API key returns `401 unauthorized` instead.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 401 Unauthorized Error

The Bearer credential is syntactically valid but its API key is invalid. Missing `Authorization` or malformed Bearer credentials return `400 invalid_authorization_header`.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 404 Not Found Error

The requested resource was not found.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 406 Not Acceptable Error

The public API returns JSON and does not expose a Server-Sent Events representation. Requests that explicitly negotiate `text/event-stream` without accepting JSON are rejected.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 409 Conflict Error

The participant is still joining (retry after `room.participant.joined`), or a request with this `Idempotency-Key` is already in progress (`code: conflict`).

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 413 Content Too Large Error

Request body exceeds the endpoint's size limit.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 415 Unsupported Media Type Error

Send JSON request bodies with `Content-Type: application/json`. The API rejects an explicitly supplied malformed or unsupported media type.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 422 Unprocessable Entity Error

The `Idempotency-Key` was reused with a different method, path, query, content type, body, or `Operation-UUID`. A key maps to one request; use a new key. See the Idempotency guide.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

### 500 Internal Server Error

An unexpected platform failure. Quote `support_id` to support; do not parse it. The technical cause and vendor event identifier are not exposed.

- `code` ("internal_error", required)
- `message` ("An internal error occurred", required)
- `support_id` (string, required) — Identifier for this error occurrence, starting with `err_`. Preserve the complete value and quote it when you contact support.

### 503 Service Unavailable Error

When an `Idempotency-Key` was supplied, the idempotency store is unavailable and the request was not processed; retry with the same key. An operation can document another `503` condition with different execution and retry guidance; follow the operation description and the Idempotency guide.

- `code` (enum, required) — Stable, machine-readable error class from a closed set. Branch on this for programmatic handling. New codes are only added with a documented API change. Maps to the HTTP status as follows: `invalid_request` (400/405/406/415/422), `invalid_authorization_header` (400), `payload_too_large` and `result_set_too_large` (413), `unauthorized` (401), `forbidden` (403), `not_found` (404), `recording_not_active` (400); `conflict`, `concurrent_recording_limit_reached`, `room_full`, and `room_not_empty` (409), `rate_limited` (429), and `unavailable` (503/529). Unexpected failures use the separate `InternalErrorResponse` schema. Several statuses map from more than one code. For `413`, `payload_too_large` means the request body exceeded its size cap, while `result_set_too_large` means a list response exceeded the overall result limit (narrow the query with filters and retry). `unavailable` maps to different retry conditions: `503` means a required store or service is temporarily unavailable, and `529` means the platform is overloaded. Use the HTTP status and operation description, not just `code`, to distinguish them.
  - Allowed values: `invalid_request`, `invalid_authorization_header`, `payload_too_large`, `result_set_too_large`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `concurrent_recording_limit_reached`, `recording_not_active`, `room_full`, `room_not_empty`, `rate_limited`, `unavailable`
- `message` (string, required) — Human-readable, English-only error message. For display only — phrasing may change without notice, so branch on `code`, not on this string.

## Types

### RoomAudienceParticipantsParticipantsItems

- `uuid` (string, required) — Session UUID of a participant who hears this participant.
- `volume` (integer, optional) — Volume at which this participant hears the whisper (1-9). 5 = normal/unchanged, 1 = quietest, 9 = loudest. It does not affect how this participant hears the room or how the room hears them, and it is independent of `POST /v1/sessions/{uuid}/room/volume`. To change it, send the audience again with the new value; only this participant's volume changes. Omitting it means 5. Responses and webhooks always include it.

## Examples

**Request**

```json
{
  "type": "nobody"
}
```

**Response**

```json
{
  "room_id": "string",
  "status": "in_progress"
}
```

**SDK Code**

```python Room Participants_setRoomParticipantAudience_example
import requests

url = "https://api.vorbal.dev/v1/sessions/uuid/room/audience"

payload = { "type": "nobody" }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Room Participants_setRoomParticipantAudience_example
const url = 'https://api.vorbal.dev/v1/sessions/uuid/room/audience';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"type":"nobody"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Room Participants_setRoomParticipantAudience_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.vorbal.dev/v1/sessions/uuid/room/audience"

	payload := strings.NewReader("{\n  \"type\": \"nobody\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Room Participants_setRoomParticipantAudience_example
require 'uri'
require 'net/http'

url = URI("https://api.vorbal.dev/v1/sessions/uuid/room/audience")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"type\": \"nobody\"\n}"

response = http.request(request)
puts response.read_body
```

```java Room Participants_setRoomParticipantAudience_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.vorbal.dev/v1/sessions/uuid/room/audience")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"type\": \"nobody\"\n}")
  .asString();
```

```php Room Participants_setRoomParticipantAudience_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.vorbal.dev/v1/sessions/uuid/room/audience', [
  'body' => '{
  "type": "nobody"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Room Participants_setRoomParticipantAudience_example
using RestSharp;

var client = new RestClient("https://api.vorbal.dev/v1/sessions/uuid/room/audience");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"type\": \"nobody\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Room Participants_setRoomParticipantAudience_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["type": "nobody"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.vorbal.dev/v1/sessions/uuid/room/audience")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```