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:
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"}'
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",
}),
});
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: each room with its clients
- Clients: each client with its rooms, credentials and relayed sessions
- Credentials: filter credentials by client
- 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:
{ "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:
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.
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.