# Clients & rooms

Clients and rooms are optional labels you attach to a credential request. They do not change how TURN works; they let you find a call, a participant or a session later in the dashboard and connect it to your own records.

## The three fields

| Field | Meaning |
|-------|---------|
| `initiator_client` | The participant that starts the connection, usually the one that creates the SDP offer |
| `receiver_client` | The participant that answers |
| `room` | The call, meeting or channel the connection belongs to |

Send any combination of them in the body of [`POST /credentials/ice`](https://turnix.io/docs/api-reference/credentials):

**cURL**

```bash
curl -X POST https://turnix.io/api/v1/credentials/ice \
  -H "Authorization: Bearer $TURNIX_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ttl": 3600, "room": "standup-2026-10-30", "initiator_client": "user-1842", "receiver_client": "user-77"}'
```

**Node.js**

```javascript
const response = await fetch("https://turnix.io/api/v1/credentials/ice", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TURNIX_API_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    ttl: 3600,
    room: "standup-2026-10-30",
    initiator_client: "user-1842",
    receiver_client: "user-77",
  }),
});
```

**Python**

```python
response = requests.post(
    "https://turnix.io/api/v1/credentials/ice",
    headers={"Authorization": f"Bearer {os.environ['TURNIX_API_TOKEN']}"},
    json={
        "ttl": 3600,
        "room": "standup-2026-10-30",
        "initiator_client": "user-1842",
        "receiver_client": "user-77",
    },
    timeout=10,
)
```

## How Turnix stores them

- Clients and rooms belong to a project and are identified by name.
- The first request with a new name creates the client or room. Later requests with the same name reuse it. There is no separate "create" call.
- When a request contains a `room`, the clients in that request are linked to the room. A room can hold any number of clients, and a client can be in many rooms.
- The credential remembers its initiator, receiver and room, so every TURN session started with it can be traced back.

In the dashboard you can then open:

- [Rooms](https://turnix.io/app/turn/rooms): each room with its clients
- [Clients](https://turnix.io/app/turn/clients): each client with its rooms, credentials and relayed sessions
- [Credentials](https://turnix.io/app/turn/credentials): filter credentials by client
- [Sessions](https://turnix.io/app/turn/sessions): TURN sessions and their traffic

## Naming rules

Values may contain only letters, digits, `-` and `_` (`^[A-Za-z0-9_-]+$`). Any other character, including spaces, dots, `@` and an empty string, makes the **whole request** fail:

```json
{ "error": "room contains invalid characters", "code": "unprocessable_entity" }
```

So omit a field instead of sending it empty, and sanitize values before you send them, for example:

```javascript
const label = (id) => String(id).replace(/[^A-Za-z0-9_-]/g, "-").slice(0, 64) || undefined;
```

Keep names short and stable. Very long values are not useful in the dashboard.

> **Warning: Do not send personal data**
>
> Everyone with access to your Turnix project can see these labels. Use internal IDs (`user-1842`) or opaque hashes, not email addresses or names.

## Patterns

**1:1 calls.** Each side requests its own credentials. Send the same `room` and the same `initiator_client`/`receiver_client` pair from both sides, so both credentials appear under one room with both participants.

**Group calls (SFU or mesh).** Send `room` and set `initiator_client` to the participant who is requesting. Leave `receiver_client` out. The room then lists everyone who joined.

**Correlating with your system.** Use the same identifiers you use in your own logs (call ID, user ID). When a user reports a bad call, you can search for the room or client in the dashboard and see which region and sessions were involved.
