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

# The video registrant lifecycle

> How Orbit models webinar registrants — the record's pre-live, during, and post-life phases; the fields the platform captures versus your custom questions; the join-token identity that gates room access; the approve-to-check-in status workflow; concurrency and privacy properties; and how registrants hang off the video room model

# The video registrant lifecycle

A registrant is a person who signed up for a scheduled video room before it
went live. Registration is a first-class video capability: the room carries
its own registration form, each signup produces a registrant record with its
own join token, and the room's join gate can refuse anyone the register does
not approve. This page explains the registrant record itself — where it
lives, which status it moves through, and how it becomes room access. The
endpoint-by-endpoint contract lives in the
[Video API reference](/api-reference/video); the step-by-step walkthrough is
the [Registration-gated webinars](/guides/video-webinars) guide. Both are
implemented on the model described here.

## When a registrant record exists

A registrant record exists across three phases of the room, and the shape of
the record is the same in all three.

* **Pre-live** — the organizer opens the room's registration form, and each
  signup appends a record to the room's register. Registration editing stays
  available while the room is pending (before it goes live). The record
  accumulates approval decisions: pending, approved, declined, blocked, or
  waitlisted.
* **During** — the join gate consults the register live. An approved
  registrant's join flips the record to attended, atomically, in the same
  step that mints their participant token. The register is a live input to
  admission, not just a pre-event list.
* **Post** — the record feeds the registered-versus-attended report: totals
  by status, no-shows (approved but never checked in), attendance rate, and
  capacity remaining. Because the register lives on the room record, the
  room's history and retention surfaces treat it as part of the room.

The register is stored on the room itself, inside the room's per-room
settings blob — so it is tenant-isolated by construction and disappears with
the room when the room is deleted. No separate registrant table exists; a
room's register never leaks across tenants or across rooms.

## Registration fields versus custom questions

The form always captures two platform fields:

* **name** — the attendee display name.
* **email** — the attendee address, deduplicated case-insensitively within
  the room (a second signup with the same email, in any case, is refused as
  a conflict).

On top of those, the organizer can attach **custom questions** — up to 20 of
them, each with a stable machine key, a human label, and a required flag.
Required questions are enforced at registration time: a submission missing a
required answer is refused. Answers are stored on the record keyed by the
question's machine key, so your form's `fractional_seats` key stays the same
field even when you relabel it.

## Check-in identity: the join token

Every registrant record carries a **join token** — an opaque, unique value
minted at registration (\~192 bits of entropy). The organizer distributes it
in the confirmation email, and the attendee redeems it at the join gate.
That token, or the registrant's email, is the identity the gate matches
against; a name alone never admits anyone.

<Note>
  The join token identifies the registrant within the one room it was minted
  for. It is not an API credential and it does not reuse the shared guest
  invite link — each registrant holds their own.
</Note>

When the room arms the **Registered participants only** switch, both paths
into the room — the authenticated join call and the guest invite redemption
— run the same register check, so there is no seam an unregistered guest can
step around. The guide to arming it is
[Registered participants only](/guides/video-webinar-registration-gate).

## Lifecycle: the status workflow

A registrant moves through statuses, and check-in sits beside the status,
not inside it:

| Status       | Meaning                                                                                  |
| ------------ | ---------------------------------------------------------------------------------------- |
| `pending`    | Registered, waiting for an organizer decision (only when the form requires approval)     |
| `approved`   | Holds a capacity slot and may join                                                       |
| `declined`   | Refused by the organizer; frees the capacity slot                                        |
| `blocked`    | Refused and treated as not welcome; also frees the slot                                  |
| `waitlisted` | Registered but no capacity slot was free (or the organizer moved them back to the queue) |

Transitions:

* **Register** — a signup lands `pending` when the form requires approval.
  Without approval, the registrant is `approved` immediately if a capacity
  slot is free, otherwise `waitlisted`. Capacity counts approved registrants
  plus anyone already checked in; the slot is claimed at approval, not at
  registration.
* **Decide** — the organizer approves, declines, blocks, or waitlists.
  Approving into a full room is refused with a conflict — capacity is
  enforced again at decision time, not just at registration.
* **Check in** — only an `approved` registrant can be marked attended;
  declining or blocking someone soft-revokes their ability to check in. A
  repeat check-in is idempotent and keeps the first timestamp.
* **Attended** — the `attended` flag and its timestamp sit beside the
  status. An approved attendee who never checked in is a **no-show**; the
  report surfaces that count explicitly.
* **Remove** — deleting the record ends the lifecycle unconditionally, for
  any status.

## Concurrency and privacy

The register is bounded and isolated by design:

* **Bounds** — a room holds at most 2,000 registrants, 20 custom questions,
  and answers up to 2,000 characters each. The bound keeps a runaway
  registration form from bloating the hot room-read path. Audiences beyond
  the room's participant ceiling belong to the broadcast surface, not the
  joinable room.
* **Tenant isolation** — the register lives on the room row in the
  workspace's own schema. A read or write is scoped to the caller's own
  workspace, and missing rooms return a plain not-found — a room's
  existence never leaks across workspaces.
* **Consent is yours to collect** — the register stores the answers your
  form asks; it does not itself send confirmations or reminders to
  registrants. If your form later markets to registrants, collect that
  opt-in as a custom question and honor it in your own messaging — Orbit's
  messaging consent controls apply to whatever you send, and the register
  simply records what the attendee answered.
* **Rate limits** — every registrant endpoint is rate-limited, so a flooded
  form cannot degrade the room or the API.

## Worked example: register, admit, join

1. **Open the form.** `PUT /video/rooms-scheduled/{roomId}/registration`
   with `enabled: true`, optionally `require_approval: true`, a `capacity`,
   and any `custom_fields`.
2. **Register the attendee.** `POST /video/rooms-scheduled/{roomId}/registrants`
   with `name`, `email`, and `custom_answers`. The response carries the
   record, including its `join_token` — pass that token to the attendee in
   the confirmation you send.
3. **Decide, if approval is required.** `PATCH /video/rooms-scheduled/{roomId}/registrants/{registrantId}`
   with `decision: "approve"` (or `decline`, `block`, `waitlist`).
4. **Join.** The attendee presents their email or join token at the gate.
   An approved match mints the participant token and flips the record to
   attended in the same atomic step.
5. **Read the report.** `GET /video/rooms-scheduled/{roomId}/registration`
   returns the config, the register, and the report: totals per status,
   attended count, no-shows, attendance rate, and capacity remaining.

Check-in can also be recorded directly —
`POST /video/rooms-scheduled/{roomId}/registrants/{registrantId}/check-in` —
for a badge desk or an external admission system; the join path is simply
the common self-service check-in.

## How registrants hang off the room model

Registration is an attachment to the scheduled-room model, not a separate
pillar:

* [The video room model](/concepts/video-room-model) owns the scheduled
  versus ad-hoc split and the join-token semantics; the registrant gate is
  the scheduled-room intent refined for a named, pre-registered audience.
* [Broadcast analytics](/concepts/broadcast-analytics-model) counts the CDN
  audience that watched without joining; the registrant report answers the
  opposite question — the named attendees who intended to join and did (or
  did not).
* Room usage, engagement, and the post-meeting report all read the room's
  session history as usual; a webinar is still a room, and the register is
  an overlay on its admission.

## See also

<CardGroup cols={2}>
  <Card title="Registration-gated webinars — guide" href="/guides/video-webinars">
    Open the form, review registrants, approve, check in, and read the report end to end.
  </Card>

  <Card title="'Registered participants only' gate" href="/guides/video-webinar-registration-gate">
    Arm the hard join gate so unmatched guests are refused at token mint.
  </Card>

  <Card title="The video room model" href="/concepts/video-room-model">
    Scheduled versus ad-hoc rooms, lifecycle, tokens, recording, and the analytics split.
  </Card>

  <Card title="Broadcast analytics" href="/concepts/broadcast-analytics-model">
    The CDN-audience metrics for viewers who watch without joining.
  </Card>

  <Card title="Video API reference" href="/api-reference/video">
    The endpoint contract for the registration and registrant management routes.
  </Card>
</CardGroup>
