> ## 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.

# 'Registered participants only' join gate

> Arm the webinar hard join gate so only people on the room's register can connect — unmatched guests are refused at token mint with a register-first message, while approved registrants join by email or join code.

# 'Registered participants only' join gate

A webinar's register and approval queue control *who may attend*, but by
default they only **how the register is filled** — a stranger opening the
room link still walked in as a plain guest. The **Registered participants
only** switch closes that walk-in path: once it is on, every join is
checked against the register and an unknown guest is refused instead of
admitted.

The check sits at token mint, not in your own code. Both ways a
participant token is issued — the authenticated join call and the guest
invite redemption — run the same gate, so there is no seam a guest can
step around. Approval decisions and the configured capacity stay the
source of truth; the gate only enforces them at the door.

## What the gate does

1. **Check the register at the door.** When armed, every join request is
   matched against the room's register by the joiner's email or join code
   (the `join_token` value each registrant record carries).
2. **Refuse the unknown.** A guest matching no register entry is denied
   with HTTP `403` and the error code `VIDEO_REGISTRATION_REQUIRED` — the
   dashboard join screen and the guest-join flow surface this as a
   "register first" prompt.
3. **Refuse the not-approved.** A matched registrant who is still
   **pending** (or on the **waitlist**, where approval is required) is
   denied with `VIDEO_REGISTRATION_PENDING`; a **declined** registrant
   with `VIDEO_REGISTRATION_DECLINED`; a **blocked** one with
   `VIDEO_REGISTRATION_BLOCKED`.
4. **Admit the approved.** An **approved** registrant claiming the last
   free seat (the organiser approved two names for one slot) is refused
   with `VIDEO_REGISTRATION_CAPACITY`. On a successful claim, the join
   also marks the registrant as attended — the same check-in flip that
   feeds the report's attendance figure.

Three consequences fall out of where the gate lives:

* **The host always joins.** The room's host steps over the gate so a
  closed room never locks out its own organiser.
* **Off means legacy behaviour.** Leave the switch off and unknown guests
  keep the permissive default — they connect as guests with no capacity
  slot claimed. This is the default for every register, so existing
  rooms change nothing until you flip the switch.
* **One gate, both doors.** Token mint and invite redemption enforce the
  same rule, so you never need to guess which path a joiner used.

## Enable the gate

1. Open **Voice → Video → Webinars** and pick the room.
2. On the **Registration** tab, toggle **Registered participants only**.
3. Save. The setting applies to the next join request — no redeploy, no
   token re-mint for already-connected participants.

The same flag travels on the registration config API — set
`require_registration` on the object alongside the other toggles:

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/video/rooms-scheduled/ROOM_ID/registration" \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "require_registration": true }'
```

Reads return the flag alongside `enabled`, `require_approval`, `capacity`,
and `custom_fields`, so you can confirm the armed state from the same
endpoint.

## What each joiner sees

| Who joins                                             | Result                                                                                          |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Host (the room's organiser)                           | Always admitted, gate bypassed                                                                  |
| Approved registrant (email or join code)              | Admitted; their seat is claimed and they are marked attended                                    |
| Pending or waitlisted registrant                      | 403 `VIDEO_REGISTRATION_PENDING` — "awaiting the host's approval"                               |
| Declined registrant                                   | 403 `VIDEO_REGISTRATION_DECLINED`                                                               |
| Blocked registrant                                    | 403 `VIDEO_REGISTRATION_BLOCKED`                                                                |
| Approved, but every approved seat was already claimed | 403 `VIDEO_REGISTRATION_CAPACITY` — raise the cap or waitlist someone                           |
| Stranger / unmatched email or code                    | 403 `VIDEO_REGISTRATION_REQUIRED` — "register first"                                            |
| Any of the above, gate **off**                        | Connects as a plain guest (pending/declined/blocked deny rules still apply to register matches) |

## Compose it with the other toggles

The four register settings answer four different questions; the gate adds
a fifth, and none of them replace the others:

* **Registration open** (`enabled`) — can people *sign up* at all. The
  gate only denies strangers when registration is enabled; a room without
  an open register behaves as before. Arm the gate when the register is
  open and you want the door to check it.
* **Require approval** — whether a sign-up waits as **pending**. With the
  gate on, those pending names get the "awaiting approval" refusal
  instead of entry; without approval, sign-ups land approved (or
  waitlisted past capacity) and the gate admits them.
* **Custom questions** — what the form asks. They shape the register the
  gate checks, nothing more.
* **Approved-attendee cap** — how many approved seats exist. A stranger's
  "roster closed" moment is exactly the gate; capacity decides the
  tie-break when two approved names race for the last seat.

Together with the waiting room, the gate covers both halves of
"who can see this webinar": the gate filters *arrivals*, the lobby
mutates *what a granted arrival may do* (publish or receive-only).

## Worked sample — mint a join token, catch the refusal

Minting a token for an unmatched identity denies exactly the envelope you
would render as "register first". A minted token for a signed-in user
matches the gate against their account email; a guest redeeming an invite
link matches by the same field they always supply — the join code each
registrant record carries in `join_token`, or their registered email.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/video/invites/INVITE_TOKEN/redeem" \
  -H "Content-Type: application/json" \
  -d '{
    "identity": "guest-stranger",
    "display_name": "Walk-in Viewer"
  }'
```

The response is `403` with:

```json theme={null}
{
  "error": {
    "code": "VIDEO_REGISTRATION_REQUIRED",
    "message": "The host requires every participant to register for this webinar. Register first, then join with the email you registered with or your join code."
  }
}
```

The same branch covers the authenticated mint path — a signed-in user's
`POST /rooms-scheduled/:id/join` carries their account email as its hint.

## Where next

* [Registration-gated video webinars](/guides/video-webinars) — open the
  form, tune approval/capacity/questions, and run the register this gate
  enforces.
* [Using a video room access token](/guides/video-room-access-tokens) —
  where a minted token actually goes (`Room.connect()`), and when an
  invite link beats a raw token.
