> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Using a video room access token

> What the access token a video room hands you is for, and exactly where and how to use it to connect a participant to the room.

# Using a video room access token

When you create a room, join a room, or a guest redeems an invite, Orbit
returns an **access token** — a short-lived JWT scoped to one room and
one identity. This is the single most common point of confusion: you
have the token in your hand, and it isn't obvious what to do with it.

The short answer: an access token is an **SDK credential**. You pass it
to the [`@orbit/media-client`](https://www.npmjs.com/package/@orbit/media-client)
SDK's `Room.connect()` call to put a participant into the live room. It
is **not** an HTTP `Authorization` header, and it is **not** a link you
send to a non-technical guest.

<Note>
  If you just want to get a person into a room and you are not building on
  the SDK, you probably want a **guest invite link**, not a raw token. Use
  the **Share** button on a room, or `POST /video/rooms-scheduled/{id}/invites`,
  to mint a link a guest can open in their browser. Reach for an access
  token only when your own client code connects to the room.
</Note>

## Where the token comes from

Three endpoints return an access token. They differ in who the token is
for, but the token itself is used the same way in every case.

| You called                                 | Field in the response | Token is for                     |
| ------------------------------------------ | --------------------- | -------------------------------- |
| `POST /video/rooms-scheduled` (create)     | `host_token`          | the creator, joining as host     |
| `POST /video/rooms-scheduled/{id}/join`    | `token`               | a named participant you mint for |
| `POST /video/invites/{inviteToken}/redeem` | `token`               | a guest redeeming a shared link  |

Each response also carries the media-server WebSocket URL you connect
to. Prefer `livekit_url`; fall back to the legacy `ws_url` alias if it
is absent.

## Step 1 — Get a token

Mint a per-participant token for an existing room. `identity` must be
unique per person in the room; `participant_tier` sets what they can do
(`viewer`, `panelist`, `host`, `hidden_supervisor`).

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/video/rooms-scheduled/{roomId}/join" \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "identity": "guest-jane",
    "display_name": "Jane Doe",
    "participant_tier": "panelist"
  }'
```

The response gives you the two values you need in the next step —
`token` and `livekit_url`:

```json theme={null}
{
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "livekit_url": "wss://media.orbit.devotel.io",
    "ws_url": "wss://media.orbit.devotel.io",
    "participant_tier": "panelist",
    "permissions": { "can_publish": true, "can_subscribe": true },
    "expires_at": "2026-05-10T15:05:00Z",
    "expires_in_seconds": 3600
  }
}
```

## Step 2 — Connect the participant with the token

Pass the token and the URL to `Room.connect()`. This is the "where do I
use it" answer: the token is the second argument to `connect()`.

```ts theme={null}
import { Room } from "@orbit/media-client";

const room = new Room();

// `wsUrl` is `livekit_url` from the response (fall back to `ws_url`).
// `token` is the JWT from the response — never a header, never a link.
await room.connect(wsUrl, token);

room.on("participantConnected", (participant) => {
  console.log(`${participant.identity} joined`);
});

// Publish camera + mic if the token's grant allows it.
await room.localParticipant.enableCameraAndMicrophone();
```

<Note>
  The upstream `livekit-client` SDK still works at the protocol level, but
  `@orbit/media-client` is the supported client. If you use `livekit-client`,
  point it at the `livekit_url` from the response — never at `livekit.cloud`,
  which was retired.
</Note>

## Respect the effective grant

`participant_tier` and `permissions` in the response are the **effective**
grant after any host-to-participant downgrade and any waiting-room clamp
— not necessarily what you requested. Check `permissions.can_publish`
before you show a publish (camera/mic) control. When `lobby_downgraded`
is `true`, an armed waiting room forced this join to receive-only
`viewer`; show a "waiting for the host to admit you" state instead of a
publish button.

## Tokens expire — re-mint before they do

An access token is valid for a limited window (`expires_in_seconds` from
issue, and an absolute `expires_at`). Re-mint a fresh token and reconnect
before `expires_at` to avoid dropping mid-session. Requesting a new token
for the same identity is safe.

## Handle it like a credential

Anyone holding a valid token joins the room as the named identity, so
treat it like a password:

* Deliver it to your client over a secure channel (your own authenticated
  API), not by pasting it into chat or email.
* Do not log it or embed it in a shareable URL.
* To invite a human who is not running your integration, send a **guest
  invite link** instead of a token — see below.

## Inviting a guest instead

If the person joining is not your own SDK client — a customer, a vendor,
anyone without your integration — mint a guest invite link rather than a
raw token. The link redeems to a token on the server for you, so the
guest never touches a JWT:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/video/rooms-scheduled/{roomId}/invites" \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "expires_in_seconds": 86400, "max_uses": 1 }'
```

Embed the returned `invite_token` in a URL and send that. In the
dashboard, the **Share** button on a room does exactly this.

## Reference

For the full request and response schema of every endpoint mentioned
here — create, join, invite, redeem, and the complete field list — see
the [Video API reference](/api-reference/video).
