Meeting Liveness Bot — Session Lifecycle¶
A bot session moves through defined states from creation until the meeting ends. Understanding these states helps you monitor calls, handle lobby delays, and correlate webhook results with participants.
In plain terms
After you start a session, the bot is created, joins the call, and begins analyzing people on camera. You can track progress through status updates and receive a webhook for each participant when their check finishes.
Bot State Machine¶
stateDiagram-v2
[*] --> bot_created: POST /api/sessions
bot_created --> joining_call
joining_call --> in_waiting_room: Lobby
joining_call --> in_call_not_recording: Admitted
in_waiting_room --> in_call_not_recording: Host admits
in_call_not_recording --> in_call_recording: Video streaming
in_call_recording --> call_ended: Meeting ends
call_ended --> done
bot_created --> fatal: Error
joining_call --> fatal: Error
in_call_recording --> fatal: Error
done --> [*]
fatal --> [*] | Status | Description |
|---|---|
bot_created | Bot provisioned with the meeting provider; not yet in the call |
joining_call | Bot is connecting to the meeting |
in_waiting_room | Bot is in the lobby waiting for the host to admit it |
in_call_not_recording | Bot joined but video is not streaming yet |
in_call_recording | Bot is recording — frame collection and liveness analysis are active |
call_ended | The meeting ended or the bot was removed |
done | Session complete; no further analysis |
fatal | Unrecoverable error — check logs or contact Moveris support. Also set when a stale session expires: the bot leaves the meeting and SSE clients receive session-status with fatal so the UI unlocks without a hard refresh. |
How to observe status: SSE on GET /api/sessions/:id/events (authenticated) or GET /api/interview/:token/events (interviewer). You can also poll GET /api/sessions/:id. These are not the same as liveness verdict webhooks—see How It Works — Two Ways You Receive Updates.
Participant Analysis Lifecycle¶
The interviewer UI uses manual scan: participants appear as Ready to scan and analysis starts only when the operator triggers it (or uses Re-scan). Frames do not auto-accumulate in the background.
stateDiagram-v2
[*] --> Joined: Participant joins
Joined --> Waiting: Camera on, awaiting trigger
Waiting --> Buffering: Interviewer starts scan
Buffering --> Analyzing: N frames collected
Analyzing --> Complete: fast-check verdict
Complete --> Waiting: Re-scan or camera off > threshold, then on
Complete --> [*]: Participant leaves | Stage | Interviewer UI label | What happens |
|---|---|---|
| Waiting | Ready to scan | Frames stream but are not buffered for analysis |
| Buffering | Scanning… | Operator triggered scan; frames accumulate to model count |
| Complete | Live / Fake | Verdict stored, SSE update, webhook fired |
| Model family | Frames required before analysis |
|---|---|
mixed-10-* | 10 |
mixed-30-* | 30 |
mixed-60-* | 60 |
mixed-90-* | 90 |
mixed-120-v2, mixed-120-v3_1_1 | 120 |
Frames are extracted from the participant's H.264 stream with FFmpeg and sent as consecutive PNG frames at native capture resolution (no downscale, no frame skipping) to the Moveris API.
On completion: verdict stored (if DB enabled), SSE update to interviewer UI, and verification.completed webhook to your backend.
Camera Toggle and Re-scan¶
flowchart LR
A[webcam_off] --> B{Off longer than threshold?}
B -->|No| C[Ignore brief glitch]
B -->|Yes| D[Reset frame buffer]
D --> E[webcam_on]
E --> F[Collect N frames again]
F --> G[New verdict + new webhook] | Setting | Default | Description |
|---|---|---|
| Camera-off threshold | ~10 seconds | Minimum time the camera must stay off before a re-scan is triggered |
Correlating Webhook Results¶
flowchart LR
subgraph Inputs
M["sessionId<br/>(POST /api/sessions)"]
P["participant_id<br/>(webhook)"]
end
subgraph Output
W["webhook session_id<br/>(UUID v5)"]
end
M --> V["uuid_v5(namespace,<br/>sessionId-participantId)"]
P --> V
V --> W Fixed namespace: 5e8cf7e0-e4c4-4b3a-8d3a-2f1c3b4a5e6f
Idempotent handling
The same participant may trigger multiple webhooks after camera toggles. Store the latest verdict per participant per meeting sessionId, or key on session_id + timestamp.
Example (Python)¶
import uuid
NAMESPACE = uuid.UUID("5e8cf7e0-e4c4-4b3a-8d3a-2f1c3b4a5e6f")
def moveris_session_id(meeting_session_id: str, participant_id: str) -> str:
name = f"{meeting_session_id}-{participant_id}"
return str(uuid.uuid5(NAMESPACE, name))
Interview Token Lifecycle¶
flowchart TB
C[POST /api/sessions] --> T[Sign interviewToken]
T --> U[Share /interview/token URL]
U --> V[GET /api/interview/token]
V --> E[SSE /api/interview/token/events]
T --> X{24h elapsed?}
X -->|Yes| R[Token rejected] | Property | Value |
|---|---|
| TTL | 24 hours from creation |
| Auth | Token only — no bot API key or Google login |
| Scope | Read-only access to one session's participant results |
Ending a Session¶
flowchart TB
A[Natural end] --> B[call_ended → done]
C[DELETE /api/sessions/:id] --> D[Bot stopped via meeting provider]
E[fatal error] --> F[Session unusable] Related¶
- How It Works — Full architecture and notification channels
- Integration Guide — Webhook payload fields
- API Reference — Session endpoints