Meeting Liveness Bot — Integration Guide¶
This guide walks through a production backend integration: credentials, session management, webhook handling, and the optional interviewer view.
In plain terms
Your server starts the bot before an interview, stores the session ID, and listens for webhook notifications when each participant is checked. You can also give an interviewer a link to watch results live—without building your own UI.
Before You Start¶
What You Need From Moveris¶
Bot API key¶
sk-bot-<key> — authenticates POST /api/sessions and related M2M routes.
Moveris API key (analysis)¶
Used by the hosted bot for POST /api/v1/fast-check. Moveris configures this on the bot service for your organization.
Bot base URL¶
Public URL of your environment (for example https://meet.example.com).
Webhook on the same API key¶
Register your HTTPS endpoint in the Developer Portal for the same Moveris API key the bot uses for analysis.
| Deliverable | Description |
|---|---|
| Bot API key | Prefixed with sk-bot-. Your backend sends it on every bot API call. |
| Moveris API key | Powers liveness analysis. Must match the key that owns your webhook configuration. |
| Bot base URL | Where your backend calls /api/sessions. |
| Org branding (optional) | Display name and logo when the bot joins a meeting. |
Contact the Moveris team for key provisioning, bot URL, org branding, and webhook setup.
What You Build¶
| Component | Responsibility |
|---|---|
| Session orchestrator | Calls POST /api/sessions when a meeting is scheduled or starts |
| Webhook receiver | HTTPS POST endpoint; verifies X-Webhook-Signature; handles verification.completed |
| Correlation store | Maps bot sessionId, participant IDs, and webhook session_id |
| Interviewer delivery (optional) | Sends /interview/<interviewToken> to human observers |
One API key for analysis and webhooks
The bot calls fast-check with your org’s Moveris API key. Webhooks fire on that same key. Register the webhook in the Developer Portal on the key Moveris assigns to your bot deployment—not a separate test key unless Moveris configures it that way.
Authentication¶
All backend requests to the bot use:
No browser login or session cookie is required for M2M integration.
The bot validates your key against the Moveris Developer Portal API and loads organization branding for the meeting.
sequenceDiagram
participant BE as Your backend
participant Bot as Meeting Liveness Bot
participant API as Moveris API
BE->>Bot: Authorization: Bearer sk-bot-*
Bot->>API: POST /api/auth/v1/org-bot-keys/validate/ body key
API-->>Bot: success envelope + org branding
Bot-->>BE: 200 session created or 401 Validate request (called by the bot, not your backend):
POST https://<moveris-api-url>/api/auth/v1/org-bot-keys/validate/
Content-Type: application/json
{ "key": "sk-bot-<your-bot-key>" }
Success (standard Moveris API envelope):
{
"data": {
"organization_id": 42,
"organization_name": "Your Organization",
"organization_slug": "your-org",
"bot_display_name": "Liveness Verifier",
"logo_url": "https://example.com/logo.png",
"primary_color": "#0066ff"
},
"success": true,
"message": "OK"
}
Keep keys on the server
Never expose the bot API key or Moveris API key in client-side code, mobile apps, or public repositories.
End-to-End Flow¶
sequenceDiagram
participant Backend as Your backend
participant Bot as Meeting Liveness Bot
participant Provider as Meeting provider
participant Moveris as Moveris API
participant Webhook as Your webhook endpoint
participant Observer as Interviewer (optional)
Backend->>Bot: POST /api/sessions + Bearer sk-bot-*
Bot->>Provider: Create bot for meeting URL
Bot-->>Backend: sessionId, interviewToken
Backend->>Observer: Share /interview/token (optional)
Provider->>Bot: WebSocket video frames
Bot->>Moveris: POST /api/v1/fast-check per participant
Moveris->>Webhook: verification.completed
Backend->>Backend: Correlate session_id to participant Integration timeline¶
flowchart TB
S1[1. Schedule / start meeting] --> S2[2. POST /api/sessions]
S2 --> S3[3. Store sessionId + interviewToken]
S3 --> S4[4. Share /interview/token optional]
S4 --> S5[5. Bot joins call]
S5 --> S6[6. Webhook verification.completed per participant]
S6 --> S7[7. Interviewer sees SSE updates optional]
S7 --> S8[8. Meeting ends or DELETE session] | Step | Action |
|---|---|
| 1 | Your workflow schedules or starts the video meeting |
| 2 | Backend calls POST /api/sessions with meetingUrl and optional model |
| 3 | Persist sessionId and interviewToken if using the interviewer view |
| 4 | Send https://<bot-url>/interview/<interviewToken> to observers (optional) |
| 5 | Bot joins automatically (may wait in a lobby) |
| 6 | Your webhook receives verification.completed for each analyzed participant |
| 7 | Observer watches live verdicts in the browser (optional) |
| 8 | Meeting ends naturally, or call DELETE /api/sessions/:id early |
See How It Works for the difference between bot status (SSE) and verdict webhooks.
Creating a Session¶
Request¶
POST https://<bot-url>/api/sessions
Authorization: Bearer sk-bot-<your-bot-key>
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
meetingUrl | string | Yes | Google Meet, Zoom, or Microsoft Teams meeting URL |
model | string | No | Mixed model alias (default mixed-10-v2 if omitted) |
targetParticipantNames | string[] | No | If set, scan only participants whose names match. See Targeted participant scanning |
excludeParticipantNames | string[] | No | Names to skip — useful for excluding interviewers or hosts |
bgSegmentation | boolean | No | Replace backgrounds with neutral grey before analysis. Defaults to the Moveris deployment setting. See Background segmentation |
faceGate | boolean | No | Enable face geometry / pose checks in the quality gate. Defaults to the Moveris deployment setting. See Frame quality gating |
Hosted service
The bot is hosted and configured by Moveris, so the meeting provider can stream frames back automatically. You do not pass any callback URL—just meetingUrl and an optional model.
Response¶
{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"botId": "bot_abc123",
"status": "bot_created",
"interviewToken": "eyJzZXNzaW9uSWQiOiI1NTBlODQwMC4uLiJ9.abc123sig",
"message": "Bot is being created and will join the meeting shortly"
}
| Field | Description |
|---|---|
sessionId | Bot session ID — store this; used to correlate webhooks and optional polling |
botId | Meeting provider’s bot identifier for this session |
interviewToken | Signed token for the read-only interviewer view (24-hour TTL) |
status | Initial bot state — see Session Lifecycle |
Model selection¶
The bot passes your model to POST /api/v1/fast-check with source: "live". Frame count follows the model alias (for example 10 frames for mixed-10-v3_1_1).
| Generation | Example aliases | When to use |
|---|---|---|
| V3.1.1 (recommended) | mixed-10-v3_1_1, mixed-30-v3_1_1, mixed-60-v3_1_1, mixed-90-v3_1_1, mixed-120-v3_1_1 | New integrations |
| V3.1 | mixed-10-v3_1, mixed-30-v3_1, mixed-60-v3_1, mixed-90-v3_1 | Deployments pinned to V3.1 |
| V3 | mixed-10-v3, mixed-30-v3, mixed-60-v3 | Deployments pinned to V3 |
| V2 | mixed-10-v2 … mixed-120-v2 | Legacy or explicit V2 requirement |
Full comparison: Overview — Models · Model Versioning & Frames
Targeted Participant Scanning¶
By default the bot scans every participant it sees on camera. Pass targetParticipantNames to scan only specific people, and excludeParticipantNames to skip others.
In plain terms
In an interview you usually want to verify the candidate, not the interviewer. Give the bot the candidate's name and it checks only them.
How matching works¶
The bot matches a participant's display name against your list in two tiers:
- Fuzzy match — handles typos, reordered names, and partial names. A close match resolves immediately with no extra calls.
- LLM confirmation (optional) — for borderline cases, a fast LLM yes/no check decides. Moveris enables this step on the bot deployment; you don't configure it.
excludeParticipantNames uses the same matching but rejects matches — put interviewer or host names there so they are never scanned.
Request example¶
Scan only the candidate, skip the interviewer:
{
"meetingUrl": "https://meet.google.com/abc-defg-hij",
"model": "mixed-10-v3_1",
"targetParticipantNames": ["John Smith"],
"excludeParticipantNames": ["Jane Doe"]
}
When a participant is matched, the bot pins their video feed and waits for them to speak before collecting frames. This ensures frames capture the person's live face rather than an idle thumbnail.
Participant stages¶
In targeted mode each matched participant moves through these stages, surfaced on the session SSE stream:
| Stage | Meaning |
|---|---|
matched | Name matched; waiting for the participant to start speaking |
accumulating | Collecting frames during active speech |
analyzing | Frames submitted to the Moveris API |
done | Verdict available |
Verdicts are still delivered through your verification.completed webhook with the same correlation rules.
Frame Quality Gating¶
Before a frame enters the accumulator, the bot evaluates it for capture quality. A rejected frame resets that participant's buffer so the liveness model still receives consecutive frames.
In plain terms
If the video is blurry, dark, or the face is missing or poorly framed, the bot discards the bad frame and starts collecting again. Your UI can show a short tip from the SSE event instead of waiting for a weak verdict.
What is checked¶
| Checks | Always on | Needs face gate |
|---|---|---|
| Blur, too-dark, too-bright | Yes | — |
| No face, multiple faces, size, margins, centering, backlit, head pose (yaw / pitch / roll) | — | Yes (faceGate: true or deployment default) |
Face checks load after a short model warmup. Until then, only blur and brightness run.
SSE event¶
Rejected frames emit frame-quality-rejected on the session events stream (throttled to about once per second per participant):
{
"participantId": "p1",
"participantName": "John Smith",
"reason": "too-blurry",
"framesCollected": 0,
"framesRequired": 10
}
Use reason to show interviewer guidance. Configure face checks with Moveris or pass faceGate on session create when your deployment allows it.
Background Segmentation¶
Optional background segmentation replaces each participant's background with neutral grey before frames go to POST /api/v1/fast-check.
In plain terms
Busy or branded meeting backgrounds can distract the model. Turning this on keeps the face and replaces everything else with a plain grey backdrop.
Pass bgSegmentation: true (or false) on POST /api/sessions. If omitted, the bot uses the deployment default from Moveris. When enabled, the analysis request includes bg_segmentation: true (same field documented on Fast Check Crops).
Receiving Results via Webhook¶
Configure your webhook in the Developer Portal on the same Moveris API key the bot uses. Subscribe to verification.completed (and optionally verification.failed).
After each participant analysis, Moveris sends an HTTP POST to your registered URL. This uses the same delivery format as the REST API—not a separate bot-specific event name.
Headers¶
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | Moveris-Webhook/1.0 |
X-Webhook-Event | verification.completed or verification.failed |
X-Webhook-Session | Moveris analysis session ID (see correlation below) |
X-Webhook-Signature | sha256=<hmac_hex> — HMAC-SHA256 of the raw body |
Payload (verification.completed)¶
{
"event": "verification.completed",
"session_id": "a3f7c291-8b2e-5c1d-9f0a-1b2c3d4e5f6a",
"timestamp": "2026-06-01T15:26:42.123456Z",
"data": {
"verdict": "live",
"real_score": 0.88,
"score": 88.0,
"confidence": 0.93,
"type": "VERY HIGH",
"session_id": "a3f7c291-8b2e-5c1d-9f0a-1b2c3d4e5f6a",
"model": "mixed-10-v3_1",
"input_source": "live",
"processing_ms": 1240,
"frames_processed": 10,
"tenant_metadata": {
"participant_id": "p1",
"participant_name": "John Doe",
"bot_session_id": "<parent_session_id>"
},
"warning": null,
"created_at": "2026-06-01T15:26:42.123456Z",
"frames": [
"https://storage.example.com/frames/.../frame-0.png?token=..."
]
}
}
| Field | Description |
|---|---|
event | Always verification.completed for a finished analysis |
session_id | Moveris analysis session ID — deterministic per bot session + participant (see below) |
timestamp | ISO-8601 time of the event |
data.verdict | "live" or "fake" |
data.score | Liveness score 0–100 |
data.real_score | Normalized score 0.0–1.0 |
data.confidence | Confidence 0.0–1.0 |
data.model | Model alias used for this analysis |
data.input_source | "live" for meeting bot captures |
data.processing_ms | Analysis duration in milliseconds |
data.frames_processed | Number of frames analyzed |
data.frames | Presigned frame URLs when retention is enabled; empty array otherwise |
Not wrapped in the API envelope
Webhook bodies are sent directly by the delivery service. They are not wrapped in { data, success, message } like REST API responses. See the Webhook Setup Guide for signature verification and failed-event examples.
Frame retention
data.frames is populated only when frame retention is enabled for your organization. URLs expire per your retention policy (typically a few minutes).
Correlating Webhooks to Participants¶
The bot assigns each participant a deterministic Moveris session ID before calling fast-check:
namespace = "5e8cf7e0-e4c4-4b3a-8d3a-2f1c3b4a5e6f"
moveris_session_id = uuid_v5(namespace, "<botSessionId>-<participantId>")
| Value | Source |
|---|---|
botSessionId | sessionId from POST /api/sessions |
participantId | ID from the meeting provider for that person |
Webhook session_id | Equals moveris_session_id for that participant |
flowchart LR
A["POST /api/sessions → sessionId"] --> C["uuid_v5(namespace, sessionId + '-' + participantId)"]
B["participantId from meeting"] --> C
C --> D["Webhook session_id"] The webhook payload does not include participant_id or participant_name. Use one of these patterns:
| Pattern | When to use |
|---|---|
| Precompute | You already know participant IDs — compute uuid_v5 and match incoming session_id |
| Poll session results | Call GET /api/sessions/<sessionId> and match results[participantId].moverisSessionId to the webhook session_id |
| Single participant | One expected participant — one webhook maps to that person |
Camera re-scan
If a participant toggles their camera off and on, the bot may send another analysis and webhook with a new session_id for the same person only if participant IDs change. Treat the latest verdict per your business rules; see Session Lifecycle.
Example (Python)¶
import uuid
NAMESPACE = uuid.UUID("5e8cf7e0-e4c4-4b3a-8d3a-2f1c3b4a5e6f")
def moveris_session_id(bot_session_id: str, participant_id: str) -> str:
return str(uuid.uuid5(NAMESPACE, f"{bot_session_id}-{participant_id}"))
def find_participant_for_webhook(bot_session_id: str, webhook_session_id: str, participant_ids: list[str]) -> str | None:
for pid in participant_ids:
if moveris_session_id(bot_session_id, pid) == webhook_session_id:
return pid
return None
Webhook Security¶
Verify X-Webhook-Signature with your webhook secret. See Webhook Setup Guide — Verifying the Signature.
Optional: Poll Session Results¶
If you need participant names or IDs alongside webhooks, poll while the meeting is active:
The response includes results keyed by participantId, each with verdict, score, moverisSessionId, and related fields. Use this to build your correlation table or to backfill if a webhook was missed.
Optional: Manual Re-scan¶
Trigger a new analysis for one or all participants (same session, bot still in call):
POST https://<bot-url>/api/sessions/<sessionId>/retry/<participantId>
POST https://<bot-url>/api/sessions/<sessionId>/retry-all
Authorization: Bearer sk-bot-<your-bot-key>
Each successful re-scan can produce another verification.completed webhook with the same correlation rules.
Interviewer View¶
The interviewToken enables a read-only live dashboard—no bot API key or Google login.
URL Format¶
What the Page Does¶
- Validates the token via
GET /api/interview/<token> - Opens SSE at
GET /api/interview/<token>/events - Shows participants and verdicts as analysis completes
The token expires 24 hours after creation.
Typical Usage¶
- Your backend creates a session before the interview.
- Extract
interviewTokenfrom the response. - Send the interview URL to the observer.
- They open it during the call and monitor results in real time.
Stopping a Session¶
Response
Error Handling¶
Bot API errors¶
| HTTP Status | Meaning |
|---|---|
| 400 | Missing or invalid meetingUrl |
| 401 | Invalid or revoked bot API key (Invalid bot key) |
| 404 | Session not found |
| 500 | Internal error — contact Moveris with sessionId and timestamp |
Analysis failures¶
If fast-check fails after validation, you may receive verification.failed instead of verification.completed. The payload includes data.error and no verdict. Subscribe to both events in the Developer Portal if you need operational alerts.
Slack Notifications¶
When enabled on your bot deployment, Moveris can post formatted liveness verdicts to a Slack channel after each participant check.
In plain terms
This is an optional operator alert channel—not a replacement for your production webhook. Moveris configures it on the bot service when your team requests Slack visibility during pilots or ongoing monitoring.
Each message includes:
- Environment label (for example Development, Staging, Production)
- Participant name and verdict (Live, Fake, Inconclusive, or Error)
- Score, model, processing time, and Moveris
session_id - Meeting URL when available
Your backend integration should still rely on verification.completed webhooks for pass/fail decisions. See How It Works — Two Ways You Receive Updates. Contact the Moveris team to enable Slack alerts on your deployment.
Production Checklist¶
- [ ] Bot API key stored in server-side secrets
- [ ] Moveris API key and webhook registered on the same Developer Portal key (configured by Moveris on the bot)
- [ ] Webhook URL is HTTPS and publicly reachable
- [ ] Signature verification implemented (
X-Webhook-Signature) - [ ] Subscribed to
verification.completed(andverification.failedif needed) - [ ] Correlation tested:
sessionId+participantId→ webhooksession_id - [ ] Model chosen (V3.1 recommended for new integrations)
- [ ] Interviewer link flow tested (if used)
- [ ]
DELETE /api/sessions/:idtested for early termination - [ ] Re-scan behavior understood if participants toggle cameras
Contact¶
For bot API key provisioning, webhook configuration, bot URL, or integration support, contact the Moveris team.
Related¶
- How It Works — Pipeline, auth, and notification channels
- Overview — Capabilities and models
- Quick Start — Minimal first session
- Session Lifecycle — Bot states and camera re-scan
- API Reference — Complete endpoint reference
- Webhook Setup Guide — Portal configuration with screenshots