# Moveris Liveness Detection API — Full Documentation > This file contains the complete Moveris API documentation in a single, > machine-readable format for AI agents and LLMs. > Source: https://documentation.moveris.com > Index: https://documentation.moveris.com/llms.txt --- ======================================================================== Source: index.md URL: https://documentation.moveris.com/ ======================================================================== # Moveris Liveness Detection API (v2) # Human Liveness Verification Liveness detection rooted in psychophysiology, not AI training. Stop spoofing attacks by detecting what deepfakes can't replicate: biology. !!! info "For decision-makers" Moveris verifies that a **real person** is in front of the camera—not a photo, video, or deepfake. Integrate it into your app with a simple REST API. Typical flow: capture video, send frames (e.g. 10 for the fast model, 30 for the balanced model), receive a live/fake result in under a second. Get Started API Reference ## Key Features ### :zap: Fast Processing Sub-second liveness detection with 10-frame analysis ### :material-api: REST API Simple REST API for easy integration with any platform ### :material-target: High Accuracy Deep learning model with confidence scoring (0-100) ### :material-code-tags: Easy Integration Simple API with JavaScript and Python examples ## At a Glance < 1s Processing time 10 Frames required 0-100 Confidence score ## Quick Links - **[How It Works](getting-started/how-it-works.md)** - Science behind liveness detection (technical and non-technical overview) - **[For Decision-Makers](getting-started/for-decision-makers.md)** - High-level overview: value, use cases, and integration paths - **[Quick Start](getting-started/quick-start.md)** - Get up and running in minutes - **[MCP](mcp/overview.md)** — Verify human presence before AI agent actions (wire transfer, signing) - **[API Key](getting-started/api-key.md)** - Obtain your API credentials - **[Code Examples](examples/javascript.md)** - Production-ready code in multiple languages - **[llms.txt](llms.txt)** - Machine-readable docs for AI agents ([full content](https://documentation.moveris.com/llms-full.txt)) - **[Glossary](glossary.md)** - Technical terms explained in plain English ## Base URL ``` https://api.moveris.com ``` ## Authentication All API requests require an API key passed in the `X-API-KEY` header. ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check" \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -d '{ ... }' ``` [Get your API key :material-arrow-right:](getting-started/api-key.md){ .md-button } ======================================================================== Source: glossary.md URL: https://documentation.moveris.com/glossary/ ======================================================================== # Glossary Terms explained in plain English. Included: product-specific terms, technical concepts, acronyms, and potentially ambiguous words. Excluded: generic business terms and roles. If a non-technical reader might ask "What does this mean?"—it's here. --- ## A ### AI Agent Software that performs tasks autonomously on behalf of a user—e.g., ChatGPT, Claude, Cowork. Moveris can verify that a live human authorized an AI agent's high-stakes action (e.g., wire transfer, contract signing). *In practice:* When an AI agent is about to execute a consequential action, it calls Moveris to verify the user is present and authorized. ### API **Application Programming Interface.** A way for software to talk to another service. In our case, you send requests to Moveris servers, and they send back answers about whether a face is live or fake. *In practice:* You call our API from your app or website to verify that a real person is in front of the camera. ### API Key A secret code that identifies you when you use the Moveris API. Think of it like a password—you must include it in every request, and you must keep it private. *In practice:* You get your API key from the Moveris Developer Portal and send it in the `X-API-Key` header. ### Adaptive Threshold A quality cutoff that adjusts to the user's environment instead of using one fixed value for everyone. In the React SDK, blur and brightness gates learn from recent camera samples so dim rooms or soft webcams can still pass usable frames. From SDK 3.22+, the adaptive curve is also tuned per platform (iOS, Android, HarmonyOS, desktop). *In practice:* `useSmartFrameCapture` calibrates blur and brightness automatically; optional `blurThreshold` / `brightnessThreshold` props set a minimum floor, not a fixed gate. ### Attestation A signed proof that a live human completed verification at a specific time. The Moveris MCP server returns attestations as JWT (ES256) so relying parties can verify them without calling the API. *In practice:* After the user passes liveness, the agent receives an attestation containing verdict, confidence, timestamp, and action description. You can store it for audit or compliance (e.g., EU AI Act Article 14). ### AUC (Area Under the Curve) A score from 0 to 1 that measures how well a model separates real faces from fakes across all thresholds. Higher is better; 1.0 is perfect. *In practice:* In the model comparison tables, a higher AUC (e.g. 0.991) means the model reliably tells live faces apart from spoofs. --- ## B ### Babel A tool that transforms modern JavaScript (or TypeScript) into code that older browsers and runtimes can run. It lets developers use the latest language features while supporting more environments. *In practice:* When you build a React or React Native app, Babel often runs behind the scenes to compile your code. ### Boolean A data type that has only two values: `true` or `false`. Used in programming and API responses to represent yes/no, on/off, or similar binary states. ### Bot Software that runs automatically without human control. Bots can be benign (e.g., search engines) or malicious (e.g., automated fraud). Moveris helps detect when a bot is trying to impersonate a human (e.g., with a photo or video instead of a live face). ### Bot API Key A secret key prefixed with `sk-bot-` that authenticates your backend's requests to the Meeting Liveness Bot. Issued per organization by Moveris staff. Distinct from your standard Moveris API key used for liveness inference. *In practice:* Send `Authorization: Bearer sk-bot-` when calling `POST /api/sessions` on the Meeting Liveness Bot. ### Background Segmentation Replacing the scene behind a person's face with a plain neutral background before running liveness analysis. Reduces distraction from branded walls, virtual backgrounds, or busy rooms. *In practice:* On the Meeting Liveness Bot, pass `bgSegmentation: true` on session create (or use the deployment default). On Fast Check Crops, set `bg_segmentation: true` if you already segmented crops yourself. ### Backend The server-side part of your application—the code that runs on your server, not in the user's browser. Your backend should add the API key and forward requests to Moveris, so the key stays secret. *In practice:* Never put your API key in frontend code. Create a backend endpoint that receives frames, adds the key, and calls Moveris. ### Base64 A way to convert binary data (like images) into text so it can be sent safely in JSON. Your frame images are sent as Base64-encoded strings. *In practice:* Instead of sending the raw image file, you convert it to a long text string that the API can decode. ### Base URL The main address where all API requests are sent. For Moveris: `https://api.moveris.com` *In practice:* Every endpoint path is added to this base URL. Example: `https://api.moveris.com/api/v1/fast-check` --- ## C ### CI (Continuous Integration) Automated pipelines that run tests, linting, and builds when you push code. CI catches errors before they reach production. *In practice:* GitHub Actions runs unit and integration tests on every pull request. ### Claude Code An AI coding assistant (by Anthropic) that runs in your terminal. It reads `CLAUDE.md` and `AGENTS.md` at session start to follow your project's rules and conventions. *In practice:* Add a `CLAUDE.md` file to your project root; Claude Code loads it automatically and follows the rules you define. ### Claude Desktop A desktop application for chatting with Claude. Can be configured as an MCP host to connect to tools like the Moveris MCP server for liveness verification. *In practice:* Configure Claude Desktop to connect to the Moveris MCP server so you can verify human presence from within a conversation. ### CNN (Convolutional Neural Network) A type of deep learning model that analyzes images by detecting patterns and features. Moveris uses CNN models for visual analysis of face frames—detecting texture, depth, and spatial patterns that help distinguish live faces from photos, screens, or masks. *In practice:* CNN models in Moveris power the hybrid and anti-spoofing pipelines, analyzing frame pixels to produce liveness scores. ### Conventional Commits A commit message format: `type(scope): description`—e.g., `feat(auth): add login`, `fix(api): handle 429 errors`. Enables automated changelogs and clear history. *In practice:* Use prefixes like `feat:`, `fix:`, `docs:`, `chore:`, `ci:` so tools can categorize commits automatically. ### CommonJS A module system for JavaScript used in Node.js. Uses `require()` and `module.exports` to share code between files. Contrast with ESM (ES Modules), which uses `import` and `export`. *In practice:* Older Node.js projects often use CommonJS. The Moveris Node.js examples show both CommonJS and ESM + TypeScript. ### Components Reusable building blocks of a user interface—buttons, forms, cards, etc. In React and React Native, you compose screens from components. The Moveris SDK provides components like `LivenessCheck` so you don't build the camera flow from scratch. *In practice:* A component is a self-contained piece of UI that you can drop into your app and customize with props. ### Confidence This field is currently reserved for future use and is functionally identical to `real_score`. Clients should use `real_score` for decision-making. ### Credits Units used to pay for API usage. Each request uses a certain number of credits. You need enough credits in your account for requests to succeed. *In practice:* If you run out of credits, the API returns an `insufficient_credits` error. ### Crops / Pre-cropped Face images that have already been cut (cropped) to show only the face. The `/fast-check-crops` endpoint accepts these instead of full frames, which can be faster. --- ## D ### Deepfake Video or images created or altered by AI to look like a real person. ### Dependency Injection A pattern where functions receive their dependencies (e.g., database, auth) as arguments instead of creating them internally. Makes code testable and modular. *In practice:* FastAPI's `Depends()` injects auth or database connections into route handlers. Moveris helps detect when someone is trying to pass off a deepfake as a live person. ### Developer Portal The Moveris web application where you manage your account: create API keys, view usage and credits, access documentation, and handle billing. Available at [developers.moveris.com](https://developers.moveris.com/). *In practice:* Sign up, create an API key, and copy it to use in your integration. --- ## E ### .env A file (often named `.env`) that stores environment variables—API keys, database URLs, and other secrets. Never commit it to version control. *In practice:* Keep `.env` in `.gitignore` and load it with a tool like `python-dotenv` or your framework's config. ### EER (Equal Error Rate) The point where a model's rate of wrongly accepting fakes equals its rate of wrongly rejecting real faces. Lower is better. *In practice:* A model with a 4% EER is more accurate than one with 9% EER. Moveris reports EER per model and frame count. ### Endpoint A specific URL path that accepts requests and returns responses. Each endpoint does a specific job (e.g. health check, liveness check). *In practice:* `/api/v1/fast-check` is the endpoint for standard liveness verification. ### Error Boundaries In React, components that catch JavaScript errors in their child tree and display a fallback UI instead of crashing. Useful for isolating failures (e.g., in a liveness check component) from the rest of the app. *In practice:* Wrap your verification flow in an error boundary so a single failed check doesn't break the entire page. ### Express.js A popular Node.js framework for building web servers and APIs. Used to create backend endpoints that receive requests and respond with data. *In practice:* The Node.js examples use Express.js to create a `/api/liveness` endpoint that accepts frames from your frontend and forwards them to Moveris with your API key. --- ## F ### FastAPI A modern Python framework for building APIs. Uses type hints, Pydantic for validation, and async support. *In practice:* The Moveris Liveness API v2 is built with FastAPI. ### FFmpeg A widely used open-source tool for processing video and audio. It can decode a video stream and extract individual image frames. *In practice:* The Meeting Liveness Bot uses FFmpeg to turn each participant's H.264 video stream into consecutive PNG frames for liveness analysis. ### Float A number with a decimal part (e.g., 0.5, 3.14, -1.0). ### Fuzzy Matching A way to match text that is close but not identical—handling typos, reordered words, or partial names. The match is approximate, not exact. *In practice:* The Meeting Liveness Bot uses fuzzy matching to pair a participant's display name (e.g. "Jon Smith") with a target name you supply (e.g. "John Smith"). Ambiguous cases can be confirmed with an LLM check. --- ## G ### .gitignore A file that tells Git which files or folders to exclude from version control. Use it to keep secrets (e.g., `.env`) and build artifacts out of the repository. *In practice:* Add `.env` and `node_modules/` to `.gitignore` so they are never committed. Used in API responses like `confidence` and `real_score` where fractional precision matters. ### Frame A single image from a video. The API analyzes multiple frames (count varies by model: e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) to determine if a face is live or fake. ### FPS (Frames Per Second) How many images (frames) are captured from video every second. For Moveris, we recommend ~10 FPS—about 10 images per second. *In practice:* If you capture 10 frames at 10 FPS, you have roughly 1 second of video. Frame count must meet your model's minimum `min_frames` (recommended: send exactly that many). ### Frame Object The structure you send for each frame: `index`, `timestamp_ms`, and `pixels` (Base64-encoded image). ### Frame Quality Gate A check that accepts or rejects each video frame before it is buffered for liveness analysis. Rejected frames reset the buffer so the model still receives consecutive frames. Used by the Meeting Liveness Bot and mirrored conceptually by SDK capture gates. *In practice:* Listen for `frame-quality-rejected` on the bot SSE stream to show interviewer tips when a frame is too blurry, dark, or poorly framed. ### Facemesh Comparison Comparison of 3D face landmark data (facemesh) between the current verification and historical sessions. Used for returning users: Moveris can confirm the person authorizing the action matches the person who enrolled. *In practice:* When `user_identifier` is provided in `verify_human_presence`, the attestation may include `facemesh_comparison` with `match_found` and `similarity_score`. A score above 0.80 indicates the same person. ### Frontend The part of your app that runs in the user's browser or on their device—the UI, forms, and client-side logic. Your frontend captures frames and sends them to your backend, which adds the API key and calls Moveris. *In practice:* Never put your API key in frontend code. The frontend sends frames to your backend; the backend calls Moveris. --- ## H ### H.264 A common video compression standard (also called AVC). It sends video efficiently as a compressed stream rather than as separate images. *In practice:* The Meeting Liveness Bot receives each participant's camera as an H.264 stream and extracts frames from it with FFmpeg—faster and lighter than sending one image per frame. ### HTTP **Hypertext Transfer Protocol.** The protocol used to send and receive data on the web. APIs typically use HTTP methods like GET (retrieve) and POST (send). Moveris is accessed over HTTPS (secure HTTP). *In practice:* When you call `fetch()` or send a request to the API, you are using HTTP under the hood. ### Header Extra information sent with an HTTP request. Headers are separate from the main body. Common ones: `Content-Type`, `X-API-Key`. *In practice:* You put your API key in the `X-API-Key` header so the API knows who is making the request. ### HttpStream An MCP transport that uses HTTP for communication. The MCP server runs as a standalone service; the host (e.g., Cowork) connects to it over the network. Use httpStream for production or remote hosts. *In practice:* Deploy the MCP server, expose it at a URL, and point the host to that URL. Contrast with stdio, where the host starts the server as a subprocess. ### Hooks Functions that React (or similar frameworks) call at specific moments—for example, when a component loads or when data changes. The Moveris SDK provides hooks like `useLivenessCheck` so you can trigger verification from your components without writing low-level code. *In practice:* Instead of managing camera and API calls manually, you use a hook and get back the result and loading state. --- ## I ### Interview Token A signed token returned when you create a Meeting Liveness Bot session. Grants read-only access to live participant verdicts at `/interview/` without login. Valid for 24 hours. *In practice:* Share the interview URL with a human observer so they can monitor liveness results during a video call. ### Integration Test Tests that run your code against real or cloned services (e.g., database, API). Slower than unit tests but catch integration issues. *In practice:* Run integration tests in CI with a real PostgreSQL clone to verify API endpoints work end-to-end. ### Integer A whole number with no decimal part (e.g., 0, 1, -5, 42). Used in programming and API fields like `index` or `score` when fractional values are not needed. ### Integration The process of connecting Moveris (or any service) into your app or workflow. An integration might involve adding the SDK, calling the API, and wiring up the results to your UI. *In practice:* "Integrating Moveris" means adding liveness verification to your sign-up, KYC, or checkout flow. --- ## J ### JWT **JSON Web Token.** A standard format for signed data that can be verified without calling the API. The Moveris MCP server returns attestations as JWT (ES256) so relying parties can validate them locally. *In practice:* After the user passes liveness, the agent receives a JWT attestation. The JWT includes an `exp` claim (TTL) so you can check if it is still valid. --- ## L ### JPEG **Joint Photographic Experts Group.** A common image format that uses lossy compression. Smaller file size than PNG but may lose some detail. PNG is recommended for Moveris frames for better liveness accuracy. ### JavaScript A programming language that runs in web browsers and on servers (via Node.js). Used to build interactive websites and, with React and React Native, mobile and web apps. *In practice:* Moveris provides JavaScript and TypeScript examples for integrating the API. ### JSON **JavaScript Object Notation.** A standard text format for exchanging data between systems. Uses key-value pairs and lists, easy for both humans and machines to read. The Moveris API sends and receives data in JSON. *In practice:* Your request body is JSON (e.g. `frames`, `session_id`). Successful API responses wrap the payload in the standard envelope: `{"data": { "verdict": "live", ... }, "success": true, "message": "OK"}` — read `data` for the result. See [Errors](api-reference/errors.md) for error responses. ### Live (Verdict) The API decided the face is from a real person in front of the camera. ### Latency The time between sending a request and receiving the response. In APIs, lower latency means a faster response. Shown in the `processing_ms` field (milliseconds). *In practice:* If latency is too high, users may abandon the verification flow. The fast model typically returns results in under 1 second. ### Liveness / Liveness Detection Checking whether a face belongs to a real, living person in front of the camera—and not a photo, screen, mask, or deepfake. *In practice:* Moveris uses biological signals (e.g. micro-movements) that are hard to fake. ### Live Check A V3-only endpoint (`POST /api/v1/live-check`) where your app sends MediaPipe Face Mesh landmarks together with each frame. The server skips its own face-mesh step and uses your landmarks, preserving signal quality for heart-rate and blink analysis. *In practice:* Use it when you already run MediaPipe in your app (or the React SDK with face detection enabled) and want the best V3 accuracy. ### Landmark / Landmarks Points that describe the position of facial features (eyes, nose, mouth outline). MediaPipe Face Mesh produces at least 468 landmarks per frame in normalized coordinates. *In practice:* The live-check endpoint expects ≥468 landmarks per frame so the server can crop the face and extract physiological signals without re-running detection. --- ## K ### KYC Know Your Customer. Regulatory process to verify a customer's identity. Moveris liveness detection is often used as part of KYC flows to prove the person is physically present. --- ## M ### Meeting Liveness Bot A Moveris service that joins video calls (Google Meet, Zoom, Microsoft Teams) through a meeting provider integration, collects participant video frames, and runs liveness detection through the Moveris API. Your backend starts sessions with a bot API key; results arrive via webhook. *In practice:* Call `POST /api/sessions` with a meeting URL before an interview. The bot joins the call and sends a webhook for each participant analyzed. ### MediaPipe Google's open-source framework for ML models (e.g., face detection). ### Monorepo A single repository that contains multiple related projects or packages. The Moveris SDK is organized as a monorepo with shared core logic (`@moveris/shared`), React package (`@moveris/react`), and React Native package (`@moveris/react-native`). ### ML Kit Google's mobile SDK for on-device machine learning. Provides face detection, barcode scanning, and other capabilities. The Moveris SDK can use ML Kit for face detection on React Native before sending crops to the API. *In practice:* ML Kit runs on the user's device, so faces can be detected and cropped without sending full frames to a server first. ### MCP (Model Context Protocol) A standard for connecting AI agents to external tools and services. The Moveris MCP server allows AI agents (e.g., Claude, Cowork) to trigger liveness verification when performing high-stakes actions on behalf of users. The agent sends the user a verification link; after the user completes the check, the agent receives a signed attestation. *In practice:* Use MCP when your AI agent needs to verify that a live human authorized an action (e.g., wire transfer, contract signing). ### MCP Host The application that connects to and runs the MCP server—e.g., Cursor, Claude Desktop, Cowork. The host spawns the server (stdio) or connects to it over HTTP (httpStream), then uses the exposed tools. *In practice:* When you "configure the host," you tell Cursor or Cowork where to find the Moveris MCP server so it can call liveness tools. --- ## N ### Node.js A JavaScript runtime that runs outside the browser, on servers or your computer. Lets you use JavaScript for backend code, APIs, and scripts. The Moveris Node.js examples use Node.js to process frames and call the API. *In practice:* Use Node.js when you need server-side liveness checks (e.g., processing uploaded videos) or a backend proxy that adds the API key. ### npm The default package manager for Node.js. Used to install libraries and tools (e.g. `npm install express sharp`). Most Node.js projects use npm to manage dependencies. *In practice:* Run `npm install` in your project to install the packages listed in `package.json`. --- ## O ### OAuth **Open Authorization.** A standard protocol for authorization that lets applications obtain limited access to user accounts (e.g., "Log in with Google") without sharing passwords. The user authorizes via a redirect flow. *In practice:* The Moveris MCP verification flow is similar to OAuth for agents: the agent gets a session URL, the user completes verification in their browser, and the agent receives a signed attestation without handling credentials. --- ## P ### PNG **Portable Network Graphics.** A common image format that supports lossless compression. Recommended for frame images sent to the API because it preserves quality better than JPEG. *In practice:* Use PNG encoding when capturing frames—better accuracy for liveness detection. ### PPG (Photoplethysmography) A technique that measures blood volume changes—typically heart rate—from skin color variations in video. Real faces show subtle pulse; photos and screens do not. Moveris uses PPG signals as a biological indicator for liveness detection. *In practice:* PPG helps detect deepfakes and screen replays because AI-generated faces lack the natural pulse visible in real skin. ### Postman A popular tool for testing and exploring APIs. Lets you send HTTP requests (GET, POST, etc.) manually without writing code. Useful for trying out Moveris endpoints before integrating them into your app. ### Pydantic A Python library for data validation using type hints. Validates request bodies, config, and responses before they reach your code. *In practice:* Define `CreateItemRequest(BaseModel)` and FastAPI automatically validates incoming JSON against it. ### pnpm A fast, disk-efficient package manager for Node.js. Alternative to npm and yarn. Use `pnpm add` instead of `npm install` to add packages. ### Pixels In the API request, this is the Base64-encoded image data for a frame. The field is named `pixels` in each frame object. ### Polling Repeatedly asking the server for status (e.g., "is the verification done?") at fixed intervals until you get a final result. Contrast with webhooks, where the server pushes results to your URL. *In practice:* If you don't use a webhook, poll `check_verification_status` every 1–2 seconds until the session is completed, failed, expired, or cancelled. ### Proxy A server that forwards requests on your behalf. A backend proxy receives requests from your frontend, adds the API key, and forwards them to Moveris—keeping the key secure. *In practice:* Your frontend calls `https://yourserver.com/api/liveness`; your backend adds the API key and forwards to `https://api.moveris.com/api/v1/fast-check`. ### Processing Time How long the server takes to analyze your frames and return a result. Shown in the `processing_ms` field (milliseconds). ### Project Root The top-level folder of your project—where `package.json`, `pyproject.toml`, or the main config file lives. Files like `CLAUDE.md` belong here. *In practice:* Place `CLAUDE.md` next to your `README.md` or `package.json`. ### Production The live environment where real users access your app—as opposed to development or staging. Production deployments should use secure configuration, rate limiting, and proper error handling. *In practice:* Before going to production, ensure your API key is stored securely (e.g., in environment variables) and that requests are proxied through your backend. ### Prompt The text or instruction you send to an AI model. In AI APIs, the prompt defines what the model should do or answer. Moveris MCP uses prompts to instruct AI agents when to trigger liveness verification. *In practice:* When building an AI agent, you design prompts that tell it to verify human presence before high-stakes actions. ### Props Short for "properties." In React and similar frameworks, props are values you pass into a component (like settings or data) so it can display or behave correctly. ### Python A popular programming language for servers, scripts, and data processing. The Moveris Python examples show how to send frames from Python to the API (e.g., from uploaded videos or OpenCV). *In practice:* Use Python when you need to process video files server-side or run liveness checks from scripts. --- ## R ### React A JavaScript library for building user interfaces. Uses components and hooks to create interactive UIs. Moveris provides React components and hooks for liveness verification. *In practice:* Import Moveris React components into your app to add a liveness check flow with minimal code. ### React Component A reusable piece of UI built with React. Components receive props and can contain state. The Moveris SDK provides React components like `LivenessCheck` for the verification flow. *In practice:* Drop a Moveris React component into your app and pass it props (e.g., `onComplete`) to customize behavior. ### React Native A framework for building mobile apps (iOS and Android) using JavaScript or TypeScript and React. You write one codebase and deploy to both platforms. Moveris offers a React Native SDK. *In practice:* Use the Moveris React Native SDK to add liveness verification to your iOS or Android app. ### Rate Limit A limit on how many requests you can make in a given period. Exceeding it returns a `rate_limit_exceeded` error. ### RGB (Red, Green, Blue) The three color channels that make up a digital image. The order of these channels matters when feeding images to a model. *In practice:* The Mixed V3.1.1 models are trained and served on canonical RGB inputs. This clean color handling is one reason V3.1.1 is more accurate than V3.1. ### Risk Level In MCP verification, the level of assurance required: `standard` (mixed-10 model, 10 frames) or `high` (mixed-30 model, 30 frames). Higher risk levels use more frames for stronger verification. *In practice:* Use `standard` for routine approvals; use `high` for wire transfers, contract signing, and regulatory actions. ### Real Score A value from 0.0 to 1.0 that represents how likely the face is to be real. Higher values mean more likely live; lower values mean more likely fake. **Use this field for decision-making** (the `confidence` field is reserved for future use and is functionally identical to `real_score`). *In practice:* The API converts this to a 0–100 `score` for display. A score of 65 or above (0.65 for `real_score`) is considered live. ### Request A message you send to the API (e.g. a POST request with frames and your API key). ### Response The message the API sends back (e.g. verdict, score, session_id). ### Rendering The process of turning your code (e.g., React components) into what the user sees on screen. When data changes, the framework re-renders to update the UI. *In practice:* After a liveness check completes, your component re-renders to show the result. ### REST **Representational State Transfer.** A style of API design that uses standard HTTP methods (GET, POST, PUT, DELETE) and URLs. Moveris is a REST API. When you see "REST" in docs, it refers to this architectural style. ### REST API A style of API that uses standard HTTP methods (GET, POST, etc.) and URLs. Moveris is a REST API. --- ## S ### SDK Software Development Kit. A package of pre-built code (components, functions, types) that makes it easier to integrate a service into your app. Moveris offers SDKs for React and React Native with ready-to-use camera and verification UI. *In practice:* Use the Moveris SDK instead of calling the API directly—it handles camera access, frame capture, and API calls for you. ### Score A number from 0 to 100 representing how likely the face is to be real. Used for display. 65–100 = live, 0–64 = fake. ### Scope (API Key Scope) A permission that restricts what an API key can do. Moveris supports scopes such as `detection:write`, `detection:read`, `session:write`, `session:read`, `session:audit`, `keys:read`, `keys:write`, `usage:read`, `credits:read`, `webhooks:read`, `webhooks:write`, `hosts:read`, and `hosts:write`. Keys with no scopes have full access (backward compatible). Keys with scopes are limited; calls requiring a missing scope return 403 with `insufficient_scope`. *In practice:* Create scoped keys in the Developer Portal for least-privilege access. Use `detection:write` only for liveness checks, or `detection:read` only for result retrieval. ### Server A computer that runs your backend code and responds to requests from clients. Your server receives frames from the frontend, adds the API key, and forwards requests to Moveris. *In practice:* Never put your API key in client-side code. Your server should add it before calling Moveris. ### Session Hijacking When an attacker steals or reuses a valid session token to impersonate a user. If someone gets your session token, they can act as you until it expires. Moveris MCP mitigates this by re-verifying human presence before high-stakes actions. *In practice:* Instead of trusting a stale session, the agent calls Moveris to confirm a live human is authorizing the action (e.g., wire transfer). ### Session ID A unique identifier you create for each verification attempt. It helps you track a specific check and appears in the API response. *In practice:* Use a UUID like `550e8400-e29b-41d4-a716-446655440000` for each new session. ### Spoofing / Spoofed Attempting to trick the system—for example, showing a photo or video of a face instead of being in front of the camera. The API tries to detect and reject these. ### Step-up Authentication Additional verification required for high-stakes actions. Instead of trusting a session token alone, you re-verify the user (e.g., with liveness) before allowing the action. *In practice:* Moveris MCP implements step-up auth: when an AI agent is about to run a consequential action, it calls Moveris to verify a live human authorized it. ### Source In the request, indicates where the frames came from: `"live"` (real-time camera) or `"media"` (file/recording). Default is `"media"`. ### stdio (Standard Input/Output) An MCP transport where the host (e.g., Cursor, Claude Desktop) starts the MCP server as a subprocess and communicates via stdin/stdout. Ideal for local development and desktop AI tools. *In practice:* Set `MCP_TRANSPORT=stdio` and configure Cursor to launch the Moveris MCP server. Contrast with httpStream for remote/production use. ### String A sequence of text characters (letters, numbers, symbols). In programming and the API, strings are enclosed in quotes—e.g., `"live"`, `"fake"`, or Base64-encoded image data. --- ## T ### Tenant Slug A short, URL-safe identifier for your organization used in **tenant-scoped** API paths—for example `acme` in `POST /api/v1/acme/video/detect`. It must match the slug configured for your org in the Developer Portal. *In practice:* Set or update it under **Settings** so async video endpoints and access checks align with your API keys. ### Temporal-Physio The model architecture used by Mixed V3, V3.1, and V3.1.1. It combines visual analysis with physiological signals (such as subtle heart-rate cues) read across many frames over time. *In practice:* Temporal-physio models need enough frames to read the time-based signal. With too few frames they may fall back to a visual-only prediction (flagged in the response `warning` field). ### TTL **Time To Live.** How long something stays valid before it expires. For sessions, TTL is how long the verification URL works (e.g., 5 minutes). For attestations, TTL is how long the signed proof can be trusted. *In practice:* Moveris session TTL defaults to 300 seconds. Completed attestations include an `expires_at` claim in the JWT so you can enforce validity independently. ### TypeScript A superset of JavaScript that adds static types. Helps catch errors earlier and improves editor support. Many React and React Native projects use TypeScript. *In practice:* The Moveris SDK ships with TypeScript definitions so your editor can suggest types and detect mistakes. --- ## U ### Unit Test Tests that run a single function or module in isolation—no database, no network. Fast and focused on logic. *In practice:* Unit tests for a `calculate_score()` function mock inputs and assert the output; they don't call the API. ### UI (User Interface) The part of an app that users see and interact with—screens, buttons, forms, etc. The Moveris SDK provides UI components so you can show the verification flow without building it from scratch. *In practice:* A "verification UI" is the screen where the user sees themselves and follows instructions to complete liveness detection. ### UX (User Experience) The overall experience a user has when interacting with your app—how easy, clear, and pleasant it is. Good UX in verification means minimal friction, clear instructions, and fast feedback. *In practice:* Time-windowed attestation balances security and UX by allowing multiple actions within a short window without re-verifying each time. ### UUID Universally Unique Identifier. A standard format for IDs that look like: `550e8400-e29b-41d4-a716-446655440000`. Uniquely identifies a session or object. --- ## V ### Video Metadata Schema A **JSON Schema** (object type with optional `properties` / `required`) stored on your organization in the Developer Portal. When set, the optional `metadata` field on **async video detect** submissions is validated against it; invalid metadata returns `invalid_metadata`. *In practice:* Define allowed keys (e.g. `session_type`, `channel`) so every video upload carries structured, validated context for your workflows. ### Verdict The API's final decision: `"live"` (real person) or `"fake"` (spoofed/not real). *In practice:* The React SDK (`@moveris/shared` **3.6.2+**) may surface verdict **`inconclusive`** when the HTTP response is successful but the payload omits `verdict`—use it as an indeterminate outcome (retry or manual review). Hard failures still raise errors. ### Verification Session In MCP, a session created by `verify_human_presence`. It has a URL the user opens to complete liveness, and moves through states: pending → in progress → completed (or failed/expired/cancelled). *In practice:* The agent creates a session, surfaces the URL to the user, and polls `check_verification_status` until completed. The session ID links all related API calls. --- ## W ### WebRTC Web Real-Time Communication—a browser technology for live peer-to-peer connections. The Moveris SDK can send liveness frames over a WebRTC DataChannel to an observer instead of repeated HTTPS uploads. *In practice:* Use `@moveris/webrtc` when your deployment includes an observer with a `/kvs/config` endpoint. Requires HTTPS in production. ### Webhook A URL your server provides. When an event occurs, Moveris sends an HTTP POST to that URL instead of you having to poll for status. You can subscribe to **`verification.completed`** (live or fake verdict) and/or **`verification.failed`** (processing error after the request was accepted). *In practice:* Register a webhook URL in the Developer Portal and choose which events to receive. Verify each request with your webhook secret, then handle `event` and `data` accordingly. --- ## 2 ### 2FA (Two-Factor Authentication) A security method that requires two forms of verification—for example, a password plus a code from your phone. Moveris liveness can serve as a second factor by proving you are physically present. --- ## X ### X-API-Key The HTTP header where you send your API key. The name is literal—it’s sent as `X-API-Key: your-api-key` in each request. --- ## Y ### Yarn A fast Node.js package manager. Alternative to npm and pnpm. Use `yarn add` to add packages to your project. ======================================================================== Source: getting-started/for-decision-makers.md URL: https://documentation.moveris.com/getting-started/for-decision-makers/ ======================================================================== # For Decision-Makers A high-level overview for product managers, QA leads, and stakeholders. Understand what Moveris does, why it matters, and how it fits into your product. ## What Moveris Does (Plain Terms) Moveris answers one question: **Is there a real, living person in front of the camera right now?** Unlike passwords or 2FA, which can be stolen or bypassed, Moveris uses biological signals that are hard to fake—subtle movements, micro-expressions, and physiological reactions that occur involuntarily. Deepfakes and AI-generated faces can look convincing, but they cannot replicate these live biological patterns. !!! info "In practice" Your app captures video from the user's camera, sends frames (e.g. 10 for the fast model, 30 for the balanced model) to Moveris, and receives a verdict: **live** (real person) or **fake** (spoofing attempt), with a confidence score. ## When to Use Liveness Detection | Use Case | Why Moveris Helps | |----------|-------------------| | **Account opening / KYC** | Prove the applicant is physically present—not a stolen identity or deepfake | | **High-value transactions** | Step-up authentication before wire transfers, contract signing, or admin actions | | **Account recovery** | Verify the person requesting access is the real account owner | | **Bot prevention** | Replace CAPTCHAs with frictionless liveness checks | | **AI agent authorization** | When AI agents perform actions on behalf of users, verify a human authorized it (see [MCP Integration](#ai-agents-and-mcp)) | ## Integration Paths (Non-Technical) | Path | Best For | Effort | Time to Integrate | |------|----------|--------|-------------------| | **SDK (React / React Native)** | Web and mobile apps | Low | 5–30 minutes | | **Direct API** | Custom stacks, backend-only flows | Medium | 1–2 hours | | **AI Agents (MCP)** | Cowork, Claude, and MCP-compatible hosts | Low (if already using MCP) | Configure MCP server | ## Developer Portal API keys, usage tracking, billing, and analytics are managed in the **Moveris Developer Portal**: [Open Developer Portal :material-open-in-new:](https://developers.moveris.com/){ .md-button .md-button--primary .developer-portal-btn-dm target="_blank" } The portal lets you: - Create and manage API keys - View usage and credits - Access interactive API docs - Monitor billing ## AI Agents and MCP Moveris offers an **MCP (Model Context Protocol) server** for AI agents. When an AI agent is about to perform a high-stakes action—e.g., signing a contract or initiating a transfer—it can call Moveris to verify that a live human authorized that action. This is step-up authentication for the agent era: the agent surfaces a verification link to the user, the user completes a short liveness check in the browser, and the agent receives a signed attestation before proceeding. !!! tip "For technical details" See the [API Reference](../api-reference/fast-check.md) and [SDK Overview](../sdk/overview.md) for implementation details. The MCP server documentation is available separately for AI agent integrations. ## Key Metrics at a Glance | Metric | Typical Value | |--------|---------------| | Verification time | < 1 second (model-dependent: 10–30 frames typical) | | Frames required | 10 | | Confidence score | 0–100 (65+ = live) | | Processing time | ~245 ms server-side | ## Next Steps - **[Quick Start](quick-start.md)** – For developers ready to integrate - **[How It Works](how-it-works.md)** – Science and technology overview - **[API Key](api-key.md)** – Obtain credentials from the Developer Portal ======================================================================== Source: getting-started/how-it-works.md URL: https://documentation.moveris.com/getting-started/how-it-works/ ======================================================================== # How It Works How Moveris detects real humans vs. spoofs—in plain terms and technical detail. !!! info "In plain terms" Moveris checks whether the person in front of the camera is real by measuring involuntary biological signals (micro-movements, physiological reactions) that AI and deepfakes cannot reliably replicate. No user actions required—just look at the camera for about 1 second. While deepfakes and AI-generated content have gotten remarkably good at mimicking human appearance, they can't fake biology. Our API analyzes involuntary physiological signals that occur naturally when real humans interact with cameras—subtle reactions that happen below conscious awareness and can't be replicated by even the most sophisticated generative models. Unlike traditional liveness detection that relies on challenge-response actions or AI model training, we've taken a fundamentally different approach rooted in psychophysiology. We measure what the body does automatically, not what it's told to do. ## The Science (Simplified) When you're alive and looking at a camera, your body is constantly generating signals—micro-expressions, subtle movements, physiological reactions that cascade through your system. These aren't things you can control or fake; they're the signature of a living, breathing human nervous system. But it goes deeper than isolated signals. Real humans exhibit cognitive coherence—the natural, split-second coordination between what you're thinking, what you're seeing, and how your body responds. When you react to a question, your pupil dilation, facial muscle timing, and micro-movements all sync in patterns that reflect actual neural processing. Deepfakes can replicate individual elements, but they struggle to maintain this multi-layered coherence across time. The signals don't just need to exist; they need to make sense together. Our technology reads these signals through standard webcams, requiring no special hardware. Within seconds, we can determine whether we're looking at a real person or a sophisticated fake. ## Why This Gets More Effective, Not Less Here's the counterintuitive part: as deepfakes improve, our approach becomes more valuable. Traditional detection methods look for flaws—artifacts, inconsistencies, or statistical fingerprints left by AI generators. As generative models evolve, they learn to eliminate these tells. It's an arms race that favors the attacker. We're not in that race. We're not looking for what's wrong with the fake—we're confirming what's present in the real. AI can learn to add realistic-looking blinks or micro-movements, but it can't generate authentic biological coherence. There's no actual nervous system processing stimuli, no real pupils responding to light changes, no genuine cognitive load creating coordinated physiological patterns. These require actual neural tissue, actual consciousness, actual life. As deepfakes reach visual perfection, the only reliable differentiator becomes: Is there a real biological system behind this? When pixels become indistinguishable, measuring the presence of life becomes the only moat that matters. That's what Moveris does. And that's why we get stronger as the synthetic world gets more convincing. ## Getting the Best Results ### Embed in Natural User Flows Our API works best when users are naturally engaged with their screen. Rather than treating liveness verification as a separate step, integrate it into existing user activities: #### Sign-in Flows During authentication while users wait #### Content Viewing While users watch content or read instructions #### Onboarding When users are focused on completing setup #### Video Calls In the background of video calls or identity verification !!! tip "Natural engagement" When users are actively doing something, their natural biological signals are strongest and most consistent. ## Camera Positioning Matters - :material-camera: Face the camera directly rather than at an angle - :material-lightbulb: Ensure adequate lighting for better visibility - :material-meditation: Stay relatively still during the brief capture window - :material-ruler: Position at a natural distance (head and shoulders framing is ideal) ## Integration Tips #### Capture Time Capture frames at ~10 FPS (count matches model: e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) #### User Feedback Provide clear UI feedback but keep it low friction #### Retry Logic Users might need 3–4 tries in poor conditions !!! info "Low friction verification" The more natural and unobtrusive the verification feels, the better the biological signals we can measure. ======================================================================== Source: getting-started/api-key.md URL: https://documentation.moveris.com/getting-started/api-key/ ======================================================================== # Obtaining Your API Key {: .api-key-page } Get your API credentials to start integrating Moveris Liveness Detection. !!! info "In plain terms" An API key is like a password that identifies your app when it talks to Moveris. You get it from the Developer Portal, and you must include it in every request. Keep it secret—never expose it in client-side code or version control. ## Getting Started 1. **Create an account** — Sign up at the Moveris Developer Portal 2. **Navigate to API Keys** — Go to your dashboard and find the API Keys section 3. **Generate a new key** — Click "Create API Key" and give it a descriptive name 4. **Copy and secure your key** — Store your API key securely (you won't be able to see it again) [Go to Developer Portal :material-open-in-new:](https://developers.moveris.com/){ .md-button .md-button--primary .developer-portal-btn target="_blank" } !!! warning "Keep your API key secure" - Never commit API keys to version control - Use environment variables on your server - Never expose keys in client-side JavaScript - Rotate keys periodically for security ======================================================================== Source: getting-started/endpoints.md URL: https://documentation.moveris.com/getting-started/endpoints/ ======================================================================== # API Endpoints Overview of all available Moveris API (v2) endpoints. !!! info "In plain terms" Moveris offers real-time and async paths. For frame-based integrations, use **fast-check**, **fast-check-stream**, or **fast-check-crops**. For pre-recorded full videos, use **video/detect** (submit once, then poll). Frame count depends on the model (for example, 10 for `mixed-10-v2`, 30 for `mixed-30-v2`). ## Base URL ``` https://api.moveris.com ``` ## Health Check | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/health` | Check service status and loaded models | [View Health Check documentation :material-arrow-right:](../api-reference/health-check.md) ## Fast Check | Method | Endpoint | Description | |--------|----------|-------------| | `POST` | `/api/v1/fast-check` | Server-side face detection (frame count matches model) | | `POST` | `/api/v1/fast-check-stream` | Send frames one-by-one; verdict when all frames received | | `POST` | `/api/v1/fast-check-crops` | Pre-cropped face verification (faster) :material-lightning-bolt:{ .badge-faster } | | `POST` | `/api/v1/live-check` | V3 batch path with client-supplied MediaPipe landmarks per frame | [View Live Check documentation :material-arrow-right:](../api-reference/live-check.md) ## V2 Upload-First Pipeline | Method | Endpoint | Description | |--------|----------|-------------| | `POST` | `/api/v2/upload` | Buffer frames (or video) during capture — no inference | | `POST` | `/api/v2/fast-check` | Run inference by `session_id` after upload completes | | `POST` | `/api/v2/live-check` | V3 live-check variant — upload frames with landmarks first | [View V2 pipeline documentation :material-arrow-right:](../api-reference/v2-pipeline.md) !!! info "v1 vs v2" v1 endpoints send all frames in the inference request. v2 uploads frames first, then calls a lightweight check with only `session_id`. Both coexist; choose based on your capture flow. The React SDK `useLivenessV2` hook targets the v2 pipeline. ## Video Detect (Async) | Method | Endpoint | Description | |--------|----------|-------------| | `POST` | `/api/v1/{tenant_slug}/video/detect` | Submit full video (file or URL) for async processing | | `GET` | `/api/v1/{tenant_slug}/video/detect/{submission_id}` | Poll status and fetch final verification result | !!! tip "When to use video/detect" Use this flow when you already have a full recorded video and want async processing. You submit once and poll by `submission_id` until completion. [View Video Detect documentation :material-arrow-right:](../api-reference/video-detect.md) ### Endpoint Comparison | Endpoint | Use Case | Face Detection | Latency | |----------|----------|----------------|---------| | `/fast-check` | Standard integration | Server-side | ~245ms | | `/fast-check-stream` | Real-time streaming | Server-side | ~245ms | | `/fast-check-crops` | Maximum performance | Client-side | Fastest | | `/live-check` | V3 with client landmarks | Client + server | ~245ms | | `/api/v2/upload` + `/api/v2/fast-check` | Upload-first flow | Server-side | Varies by upload chunks | !!! tip "Choose the right endpoint" - Use **fast-check** for simple integrations where you send all frames at once (count depends on model) - Use **fast-check-stream** when capturing frames in real-time from a camera - Use **fast-check-crops** for the fastest processing when you can do face detection client-side !!! info "Recommended models" Use **`mixed-30-v2`** (Balanced) for most integrations. See [Models overview](../models/overview.md) for frame counts and performance characteristics. ======================================================================== Source: getting-started/authentication.md URL: https://documentation.moveris.com/getting-started/authentication/ ======================================================================== # Authentication All API requests require authentication using your API key. !!! info "In plain terms" Every request to the API must include your API key in the `X-API-Key` header. Without it, the API returns 401 Unauthorized. Never put the API key in client-side JavaScript—use a backend proxy that adds the key before calling Moveris. ## API Key Authentication Include your API key in the request header using the `X-API-Key` header. ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check" \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -d '{ ... }' ``` ## Example with JavaScript ```javascript const response = await fetch('https://api.moveris.com/api/v1/fast-check', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'your-api-key' }, body: JSON.stringify({ session_id: crypto.randomUUID(), source: 'live', frames: frames }) }); ``` Successful responses use the standard [HTTP envelope](../api-reference/errors.md): read `data` for `verdict`, scores, and metadata. Errors use `success: false` and an `errors` array. ## Example with Python ```python import requests response = requests.post( 'https://api.moveris.com/api/v1/fast-check', headers={ 'Content-Type': 'application/json', 'X-API-Key': 'your-api-key' }, json={ 'session_id': str(uuid.uuid4()), 'source': 'live', 'frames': frames } ) ``` !!! warning "Keep your API key secure" Never expose your API key in client-side code. Always make API calls from your server. ## API Key Scopes API keys can be restricted by scope for least-privilege access. When creating a key in the Developer Portal, you can assign scopes such as:
| Scope | Description | |-------|-------------| | `detection:write` | Submit liveness checks (Fast Check, Fast Check Stream, Fast Check Crops, Verify) | | `detection:read` | Retrieve detection results and queue stats | | `session:write` | Create and manage MCP verification sessions | | `session:read` | View session status and metadata | | `session:audit` | Record audit events on active sessions | | `keys:read` | List and read API keys | | `keys:write` | Create, update, revoke API keys | | `usage:read` | View usage logs and analytics | | `credits:read` | View credit balance and plan info | | `webhooks:read` | List webhook configurations | | `webhooks:write` | Create, update, delete webhook configs | | `hosts:read` | List allowed CORS origins | | `hosts:write` | Manage allowed CORS origins | Keys with **no scopes** (empty list) have full access—this preserves backward compatibility with existing keys. Keys with scopes are restricted: a request using a key that lacks the required scope returns 403 with `error: "insufficient_scope"` and `required_scope` in the response. See [Errors](../api-reference/errors.md#insufficient-scope-403) for handling. ### Creating API Keys with Scopes Create scoped API keys in the [Developer Portal](https://developers.moveris.com/) when creating a new key: 1. **Navigate to API Keys** — From the dashboard, go to **API Keys** and click **Create API Key**. 2. **Name your key** — Enter a descriptive name (e.g., "Production detection key"). 3. **Select scopes** — Choose the scopes this key will have. Leave empty for full access, or select only the scopes you need for least-privilege access. 4. **Create and copy** — After creation, copy the key—you will not be able to see it again. !!! example "Screenshot: Create API Key form" ![Create API Key form with scopes selector](../assets/images/authentication/api-key-create-scopes.png) !!! example "Screenshot: Scopes selector" ![Scopes selector in Create API Key](../assets/images/authentication/api-key-scopes-selector.png) ## Security Best Practices 1. **Store keys in environment variables** - Never hardcode API keys in your source code 2. **Use a backend proxy** - Client-side apps should call your backend, which adds the API key 3. **Rotate keys regularly** - Generate new keys periodically and revoke old ones 4. **Monitor usage** - Watch for unexpected spikes that might indicate compromised keys ======================================================================== Source: getting-started/quick-start.md URL: https://documentation.moveris.com/getting-started/quick-start/ ======================================================================== # Quick Start Guide {: .quick-start-page } Get up and running with Moveris Liveness Detection in minutes. !!! info "In plain terms" Capture frames from the camera (count depends on model—e.g. 10 for mixed-10-v2, 30 for mixed-30-v2), encode them as base64, send them to the API with your API key, and receive a live/fake verdict with a confidence score. The code examples below show the full flow. !!! tip "Using React or React Native?" The official SDK provides ready-to-use components and hooks for the fastest integration. See the [SDK Documentation](../sdk/overview.md) to get started in 5 minutes. ## Prerequisites - A Moveris API key ([Get one here](api-key.md)) - Access to a webcam or video source - A server environment to keep your API key secure ## Basic Flow 1. Capture 10 video frames from user's camera (~1 second at 10 FPS) 2. Encode frames as base64 PNG 3. Send frames to Moveris API with your API key 4. Receive verdict ("live" or "fake") with confidence score ## Code Examples === "JavaScript" ```javascript async function checkLiveness(videoElement) { const frames = []; // Capture frames (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) const frameCount = 10; for (let i = 0; i < frameCount; i++) { const canvas = document.createElement('canvas'); canvas.width = 640; canvas.height = 480; const ctx = canvas.getContext('2d'); ctx.drawImage(videoElement, 0, 0, 640, 480); frames.push({ index: i, timestamp_ms: performance.now(), pixels: canvas.toDataURL('image/png').split(',')[1] }); // Wait ~100ms between frames (10 FPS) await new Promise(r => setTimeout(r, 100)); } const response = await fetch('https://api.moveris.com/api/v1/fast-check', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'sk-your-api-key' }, body: JSON.stringify({ session_id: crypto.randomUUID(), source: 'live', model: 'mixed-10-v2', frames: frames }) }); const body = await response.json(); if (!body.success) { throw new Error(body.message ?? 'Request failed'); } return body.data; } ``` === "Python" ```python import base64 import uuid import cv2 import requests def check_liveness(video_path: str, api_key: str) -> dict: """Check liveness. Frame count matches model (e.g. 10 for mixed-10-v2).""" cap = cv2.VideoCapture(video_path) frames = [] for i in range(10): # 10 for mixed-10-v2 ret, frame = cap.read() if not ret: break frame = cv2.resize(frame, (640, 480)) _, png_data = cv2.imencode('.png', frame) pixels = base64.b64encode(png_data.tobytes()).decode('utf-8') frames.append({ 'index': i, 'timestamp_ms': i * 100, 'pixels': pixels }) cap.release() response = requests.post( 'https://api.moveris.com/api/v1/fast-check', headers={ 'Content-Type': 'application/json', 'X-API-Key': api_key }, json={ 'session_id': str(uuid.uuid4()), 'source': 'live', 'model': 'mixed-10-v2', 'frames': frames } ) body = response.json() if not body.get("success", False): raise RuntimeError(body.get("message", "Request failed")) return body["data"] ``` !!! tip "Frame Capture" Frame count must match your model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). Capture at ~10 FPS. For mixed-10-v2, that's about 1 second of video. ## Next Steps - [Fast Check API Reference](../api-reference/fast-check.md) — Complete API documentation - [JavaScript Examples](../examples/javascript.md) — Full implementation examples - [Fast Check Crops](../api-reference/fast-check-crops.md) — Faster processing option - [Frame Capture Guidelines](../best-practices/frame-capture.md) — Best practices for capture ======================================================================== Source: ai-development/vibe-coder-guide.md URL: https://documentation.moveris.com/ai-development/vibe-coder-guide/ ======================================================================== # Vibe Coder Guide Ready-to-use prompts for AI coding tools. Just copy, paste into your favorite AI assistant, and go. !!! info "In plain terms" Use these pre-written prompts with AI assistants (Lovable, Cursor, Bolt, Replit) to generate liveness detection code. Copy the prompt, paste it into your AI tool, add your API key, and you get a working integration. No manual coding required. ## How to Use This Guide ### 1. Copy the Prompt Find the prompt for your AI tool and click the copy button. ### 2. Paste & Generate Paste into Lovable, Cursor, Bolt, or your preferred AI tool. ### 3. Add Your API Key Replace the placeholder with your Moveris API key and you're done! ## Quick Reference | Setting | Value | |---------|-------| | Base URL | `https://api.moveris.com` | | Endpoint | `/api/v1/fast-check` | | Frames Required | Depends on model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) @ ~10 FPS | | Response | JSON envelope: `success`, `message`, and `data` (verdict, scores, etc.) — see [Errors](../api-reference/errors.md) | --- ## Prompts by AI Tool ### Lovable
Lovable ```markdown Add Moveris liveness detection to my app. Requirements: - Create a React component with webcam access using getUserMedia - Capture frames at ~10 FPS (count = model min_frames, e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) - Encode frames as base64 PNG - Send to https://api.moveris.com/api/v1/fast-check - Use X-API-Key header for authentication - Display verdict (live/fake) and confidence score - Handle loading and error states Request body format: { session_id: crypto.randomUUID(), source: "live", model: "mixed-10-v2", frames: [{ index, timestamp_ms, pixels }] } Important: API calls should go through a backend/edge function to protect the API key. ``` ### Cursor / GitHub Copilot
Cursor / GitHub Copilot ```markdown Create a liveness detection integration with Moveris API (v2). Tech stack: React with TypeScript API endpoint: POST https://api.moveris.com/api/v1/fast-check Auth: X-API-Key header Requirements: 1. Capture frames (count matches model, e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) at ~10 FPS from webcam 2. Encode each frame as base64 PNG data URL 3. Generate unique session_id using crypto.randomUUID() Request body structure: { session_id: string, source: "live", model: "mixed-10-v2", frames: [ { index: number, timestamp_ms: number, pixels: string } ] } Response structure (HTTP JSON envelope — read `data` for the result): { success: boolean, message: string, data: { verdict: "live" | "fake", confidence: number (0-100), real_score: number (0.0-1.0), score: number (0-100) } | null, errors: array (when success is false) } Generate a complete, production-ready implementation with: - Custom React hook for reusability - Proper error handling for 401, 429, and 500 errors - Loading states and user feedback - TypeScript interfaces for type safety ``` ### Bolt
Bolt ```markdown Build a webcam liveness verification feature using Moveris API. Steps: 1. Access user's camera with getUserMedia 2. Show live camera preview 3. On button click, capture frames (e.g. 10 for mixed-10-v2) over ~1 second 4. Send frames to https://api.moveris.com/api/v1/fast-check 5. Show live/fake result with confidence percentage API Details: - Method: POST - Header: X-API-Key: (use environment variable) - Body: { session_id: UUID, source: "live", model: "mixed-10-v2", frames: [{index, timestamp_ms, pixels}] } - Response: JSON envelope with `data.verdict`, `data.score` / confidence fields (see API reference) Include a nice UI with: - Camera preview with face guide overlay - "Verify" button with loading state - Result display showing verdict and confidence - Error handling with user-friendly messages ``` ### Replit / Python
Replit / Python ```markdown Create a Python Flask API endpoint for liveness detection using Moveris. Endpoint: POST /verify-liveness Accept: multipart/form-data with image files (count = model min_frames, e.g. 10 for mixed-10-v2) Implementation: 1. Receive uploaded image files (count matches model) 2. Convert each to base64 PNG 3. Call Moveris API at https://api.moveris.com/api/v1/fast-check 4. Return the verdict and confidence Moveris request format: { "session_id": "uuid-string", "source": "live", "model": "mixed-10-v2", "frames": [ {"index": 0, "timestamp_ms": 0, "pixels": "data:image/png;base64,..."} ] } Use X-API-Key header with API key from environment variable. Parse Moveris JSON: check `success`, then use `data` for verdict/scores; on failure use `message` / `errors`. Your Flask response can mirror that or unwrap `data` for the client. ``` --- ## Key Concepts Explained !!! info "What's a session_id?" A unique ID for each verification attempt. Just use `crypto.randomUUID()` — it generates one automatically! Each liveness check should have its own session_id. !!! info "What's base64?" A way to turn images into text so they can be sent in JSON. The code examples handle this automatically using canvas.toDataURL() or similar methods. !!! info "Why multiple frames?" Moveris analyzes multiple frames to detect subtle signs of life. Frame count varies by model: 10 for mixed-10-v2 (fastest), 30 for mixed-30-v2 (recommended), and so on. Capture at ~10 FPS. !!! info "What's the verdict?" Inside the response `data` object, the API returns either `"live"` (real person) or `"fake"` (spoofing attempt), along with scores (see field names in the [Fast Check](../api-reference/fast-check.md) reference). --- ## Customization Prompts Add these to your chat to enhance your implementation: ### Add retry logic for rate limiting ```markdown Add exponential backoff retry logic to handle 429 rate limit errors. Retry up to 3 times with increasing delays. ``` ### Use faster crops endpoint ```markdown Switch to the /fast-check-crops endpoint with MediaPipe face detection. Crop faces to 224x224 before sending for faster processing. ``` ### Add backend API proxy ```markdown Create a backend/edge function to proxy Moveris API calls. The frontend should call our backend, which adds the API key and forwards to Moveris. This protects our API key. ``` ### Support mobile camera ```markdown Update the camera component to use the front-facing camera by default on mobile devices. Add facingMode: "user" to the getUserMedia constraints. ``` ### Add face detection overlay ```markdown Add a face detection overlay using MediaPipe that shows a bounding box around the detected face. Only enable the verify button when a face is detected. ``` --- ## Troubleshooting Prompts ### Getting 401 Unauthorized errors ```markdown Debug my Moveris API integration. I'm getting 401 errors. Check that the X-API-Key header is being sent correctly and the API key format is valid (should start with sk-). ``` ### API is slow or timing out ```markdown Optimize my liveness check for speed. Switch to the /fast-check-crops endpoint, add request timeout handling, and show a progress indicator to users. ``` ### Camera not working on mobile ```markdown Fix mobile camera access issues. Ensure we're requesting camera permissions correctly, using HTTPS (required for getUserMedia), and handling permission denied gracefully. ``` --- ## Need More Details? These prompts cover the basics. For advanced implementations, check out our detailed code examples: - [JavaScript Examples](../examples/javascript.md) - [React Examples](../examples/react.md) - [Python Examples](../examples/python.md) - [Fast Check API Reference](../api-reference/fast-check.md) - [MCP](../mcp/overview.md) — Verify human presence before AI agent actions (wire transfer, signing, etc.) - [llms.txt](../llms.txt) — Feed the full Moveris documentation to any AI agent in one request ([full content](https://documentation.moveris.com/llms-full.txt)) ======================================================================== Source: ai-development/claude-code-integration.md URL: https://documentation.moveris.com/ai-development/claude-code-integration/ ======================================================================== # Claude Code Integration Set up project rules that Claude Code reads automatically every session — so your AI assistant follows your conventions from the first prompt. !!! info "In plain terms" Claude Code is an AI coding assistant that runs in your terminal. When you add a `CLAUDE.md` file to your project root, Claude reads it at startup and follows the rules inside — coding style, architecture, do's and don'ts — without you having to repeat them every time. ## How It Works Claude Code looks for a `CLAUDE.md` file in your project root when a session starts. Everything inside that file becomes context for the entire conversation. Think of it as a persistent briefing that tells Claude: - What your project does and how it's structured - Which patterns and conventions to follow - What to avoid (e.g., modifying shared models, hardcoding secrets) - How to run tests and deploy Because the file is read automatically, you don't need to copy-paste rules into each prompt. Write them once, and every session starts with the right context. !!! tip "Works with AGENTS.md too" Claude Code also reads `AGENTS.md` if present. Use `CLAUDE.md` for rules and constraints; use `AGENTS.md` for architecture context and onboarding. Both are read at session start. --- ## Quick Start ### 1. Download the Template Get the starter `CLAUDE.md` and place it in your project root. ### 2. Customize the Rules Replace the placeholders with your project's name, stack, patterns, and conventions. ### 3. Start a Session Open Claude Code in your project. It reads `CLAUDE.md` automatically — no extra setup needed. [Download CLAUDE.md Template](../assets/downloads/CLAUDE.md.txt){ .md-button .md-button--primary .developer-portal-btn-dm download="CLAUDE.md" } !!! info "Template scope" The downloadable template is for **projects integrating with the Moveris API** — your app captures video frames and calls the API for liveness verification. It includes endpoints, models, security rules, and code patterns. Customize the identity section with your project name and stack. --- ## What to Include in CLAUDE.md A good `CLAUDE.md` covers identity, critical rules, and patterns. The Moveris template emphasizes integration rules. Below are examples; the download includes Moveris-specific content ready to use. ### 1. Project Identity Tell Claude what it's working on. This prevents wrong assumptions about your stack. ```markdown ## Project Identity **Name**: [Your Project Name] **Type**: [Your stack, e.g. Next.js, Express, FastAPI] **Integration**: Moveris Liveness API v2 **Base URL**: https://api.moveris.com **Docs**: https://documentation.moveris.com ``` !!! info "In practice" Without this section, Claude may guess your framework or language version. Replace the placeholders with your project name and stack. ### 2. Critical Rules The non-negotiable constraints. These are the rules Claude must never break. For Moveris integration, focus on security and API usage: ```markdown ## Critical Rules ### NEVER Expose API Keys in Client-Side Code Always proxy requests through your backend. Your backend adds the X-API-Key header before forwarding to Moveris. ### ALWAYS Store API Keys in Environment Variables Never hardcode credentials in source code. ### ALWAYS Validate the Verdict Server-Side Never trust client-side liveness results. Verify the verdict on your server before granting access. ### Frame Count Must Match the Model Send exactly the number of frames the model expects (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). ``` !!! tip "Best practice" Use strong verbs — NEVER, ALWAYS, MUST — for rules that have no exceptions. Claude treats these as hard constraints. ### 3. Code Patterns Show Claude how you write code in this project. Include short, realistic examples. The Moveris template includes integration patterns (backend proxy, fast-check, fast-check-stream) and code snippets for calling the API. !!! note "Beyond the template" If your project has internal structure (routes, services, etc.), add sections 4 and 5. The Moveris template focuses on integration rules rather than internal project layout. ### 4. Project Structure (Optional) Map out the project layout so Claude can place new code correctly. ```markdown ## Project Structure routes/ — API endpoints (one file per feature) services/ — Business logic (no HTTP dependencies) schemas/ — Pydantic models (requests, responses, common) auth/ — Authentication and authorization core/ — Base classes and utilities ``` ### 5. Environment & Testing (Optional) Tell Claude how to run the project and what testing standards to follow. For Moveris integration, the key variable is `MOVERIS_API_KEY`. ```markdown ## Environment Variables ### Required - DATABASE_URL — PostgreSQL connection string - API_SECRET_KEY — Secret key for signing ## Testing - Unit tests for services/ (no external dependencies) - Integration tests for API endpoints - Target >80% coverage - Run: make test ``` ### 6. Do / Don't Rules A quick-reference checklist. Claude scans these as guardrails. ```markdown ## Do - Use async for all I/O operations - Store secrets in environment variables - Write tests for business logic ## Don't - Hardcode URLs or credentials - Use blocking I/O in async contexts - Commit .env files ``` --- ## Implementation Best Practices These patterns come from real production projects. They work across Python, TypeScript, and polyglot stacks. ### Type Safety | Language | Rule | |----------|------| | Python | Full type hints on every function. Use `X \| None` instead of `Optional[X]`. | | TypeScript | Strict mode enabled. Never use `any` — use `unknown` with type guards. | ### Configuration All configuration must come from environment variables. Never hardcode URLs, credentials, or feature flags. ```python # GOOD — reads from environment settings = get_settings() db_url = settings.database_url # BAD — hardcoded value db_url = "postgresql://localhost/mydb" ``` ### Error Handling Use custom exception classes. Return structured error responses with a machine-readable code and a human-readable message. ```python class InsufficientCreditsError(AppError): status_code = 402 error_code = "insufficient_credits" ``` ### Testing Standards - **Unit tests** for business logic — no database, no network - **Integration tests** for API endpoints — use real or cloned databases in CI - **Coverage target**: 80% or higher - **Test data**: Use identifiable patterns (e.g., `test-*` prefixes) for automatic cleanup ### Git Conventions - **Branches**: `main` (production), `develop` (integration), `feature/*`, `hotfix/*` - **Commits**: Conventional Commits format — `feat:`, `fix:`, `docs:`, `chore:`, `ci:` - **Pre-push**: Run `make pre-push` (lint + format + typecheck + test) before pushing --- ## Do / Don't Reference A consolidated checklist you can copy into your `CLAUDE.md`. ### Do | Practice | Why | |----------|-----| | Use type hints on every function | Prevents runtime errors and improves editor support | | Validate all input at the boundary | Stops bad data before it reaches business logic | | Use async/await for I/O | Avoids blocking the event loop in async frameworks | | Store secrets in environment variables | Keeps credentials out of source control | | Write tests for business logic | Catches regressions early, enables safe refactoring | | Use structured logging | Makes debugging and monitoring easier in production | | Keep services free of HTTP dependencies | Business logic stays testable and reusable | | Use Conventional Commits | Enables automated changelogs and clear history | ### Don't | Practice | Risk | |----------|------| | Hardcode URLs, credentials, or config | Secrets leak; breaks across environments | | Skip input validation | Injection attacks, corrupt data, crashes | | Use blocking I/O in async contexts | Freezes the entire server under load | | Commit `.env` files or secrets | Credentials exposed in version control | | Use `any` (TS) or skip type hints (Python) | Hides bugs; loses editor autocomplete | | Put business logic in route handlers | Untestable, tightly coupled to framework | | Ignore linter warnings | Technical debt accumulates silently | | Modify shared/external models | Breaks other services that depend on the same schema | --- ## MCP Server Configuration (Optional) If your project exposes or consumes an MCP server, document it in `CLAUDE.md` so Claude understands the tools available. !!! info "In plain terms" MCP (Model Context Protocol) lets AI agents connect to external tools and services. If your project has an MCP server, documenting it in `CLAUDE.md` helps Claude understand what tools it can call and how they work. ### What to Document 1. **Server identity** — name, transport (stdio or httpStream), entry point 2. **Available tools** — name, parameters, what each tool does 3. **Environment variables** — secrets and configuration the server needs 4. **Error handling** — how the server reports errors to the agent ### Example MCP Section ```markdown ## MCP Server This project includes an MCP server for liveness verification. ### Transport - **Local (development)**: stdio — the host starts the server as a subprocess - **Remote (production)**: httpStream — deploy and connect over HTTP ### Tools | Tool | Description | |------|-------------| | verify_human_presence | Start a liveness session for the user | | check_verification_status | Poll session status until complete | ### Configuration Set these environment variables before starting: - MCP_TRANSPORT — stdio or httpStream (default: stdio) - MOVERIS_API_KEY — Your Moveris API key - MOVERIS_API_URL — API base URL (default: https://api.moveris.com) ``` ### Host Configuration Show Claude how to configure the MCP host (Cursor, Claude Desktop, etc.): ```json { "mcpServers": { "moveris": { "command": "npx", "args": ["-y", "@moveris/mcp-server"], "env": { "MOVERIS_API_KEY": "sk-your-api-key" } } } } ``` !!! warning "Security" Never commit MCP configuration files that contain API keys. Add them to `.gitignore` and use environment variables or secret managers instead. --- ## Tips for Effective CLAUDE.md Files 1. **Start small** — Project identity + 3-5 critical rules is enough to begin 2. **Use strong verbs** — NEVER, ALWAYS, MUST make rules unambiguous 3. **Show, don't tell** — Include short code examples for each pattern 4. **Update regularly** — When conventions change, update `CLAUDE.md` immediately 5. **Keep it under 500 lines** — Too long and the important rules get lost in noise 6. **Test it** — Start a fresh Claude session and see if it follows your rules without reminders --- ## Related - [Vibe Coder Guide](vibe-coder-guide.md) — Ready-to-use prompts for AI coding tools - [llms.txt](../llms.txt) — Machine-readable documentation index for AI agents ([full content](../llms-full.txt)) - [MCP Overview](../mcp/overview.md) — How AI agents verify human presence - [MCP Agent Configurations](../mcp/agent-configurations.md) — Set up Cursor and Claude Desktop as MCP hosts ======================================================================== Source: models/overview.md URL: https://documentation.moveris.com/models/overview/ ======================================================================== # Models Moveris offers **Mixed V2**, **Mixed V3**, **Mixed V3.1**, and **Mixed V3.1.1** model families to match different integration needs. The comparison table below covers **Mixed V2**; see [Mixed V3 Models](#mixed-v3-models), [Mixed V3.1 Models](#mixed-v31-models), and [Mixed V3.1.1 Models](#mixed-v311-models) for newer generations.
Fast Balanced Recommended Thorough Extended Maximum
Model ID mixed-10-v2 mixed-30-v2 mixed-60-v2 mixed-90-v2 mixed-120-v2
Frames 10 30 60 90 120
Capture time ~0.3 s ~1 s ~2 s ~3 s ~4 s
Response time ~1 s ~3 s ~5 s ~7 s ~10 s
EER 4.4% 4.0% 4.7% 5.7% 4.6%
AUC 0.988 0.991 0.991 0.989 0.991
Balanced accuracy 95.2% 95.7% 95.2% 94.3% 94.7%
Best for Low-friction, high-volume flows Standard KYC & identity verification High-security onboarding Escalation, compliance-heavy flows Highest scrutiny, regulatory edge cases
!!! info "Model cards" Detailed model cards with full metrics and evaluation data are available in the [Developer Portal](https://developers.moveris.com/model-cards){: target="_blank" rel="noopener" }. Sign in to access them. !!! tip "Not sure? Start with **Balanced (`mixed-30-v2`)** or **V3.1.1 (`mixed-30-v3_1_1`)**" **Mixed V2:** `mixed-30-v2` delivers strong overall accuracy (4.0% EER, 0.991 AUC) with ~1 second of capture. **Mixed V3.1.1:** `mixed-30-v3_1_1` is the latest 30-frame generation. Prefer V3.1.1 for new integrations when your deployment supports it. ## Mixed V3 Models Mixed V3 is the next-generation model family, available at 10, 30, and 60 frames.
Fast (V3) Balanced (V3) Thorough (V3)
Model ID mixed-10-v3 mixed-30-v3 mixed-60-v3
Frames 10 30 60
Notes Often visual-only Often visual-only Full temporal-physio fusion
V3 models use a temporal-physio architecture: visual analysis combined with physiological signals (e.g. heart-rate cues) across frames. Reliable physiological extraction needs enough temporal coverage, so `mixed-60-v3` runs full fusion. At 10 or 30 frames the physiological signal is often unavailable, and the model falls back to a **visual-only** prediction (flagged via the response `warning` field). Use V3 when your deployment supports it. ## Mixed V3.1 Models Mixed V3.1 is the **latest model generation**. Four frame counts ship in production: 10, 30, 60, and 90.
10f 30f 60f 90f
Model ID mixed-10-v3_1 mixed-30-v3_1 mixed-60-v3_1 mixed-90-v3_1
Frames 10 30 60 90
Recommended for Lowest latency, new integrations Default V3.1 choice Best attack rejection (V3.1) Extended temporal coverage
!!! info "V3.1 vs V2" V3.1 models use a different architecture and scoring regime than Mixed V2. Pin an explicit alias (`mixed-30-v3_1`, not `mixed-30-v2`) when migrating. See [Model Versioning & Frames](versioning-and-frames.md). ## Mixed V3.1.1 Models Mixed V3.1.1 is the **latest model generation** and a clean retrain of the V3.1 temporal-physio family. Five frame counts ship in production: 10, 30, 60, 90, and 120.
10f 30f 60f 90f Recommended 120f
Model ID 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
Frames 10 30 60 90 120
Recommended for Lowest latency, new integrations Default V3.1.1 choice High-security onboarding Best overall accuracy (ship config) Maximum temporal coverage
V3.1.1 was retrained on clean, canonical Red-Green-Blue (RGB) inputs and recalibrated on the real-world holdout set, where the equal error rate (EER) drops to roughly 5–9%. The architecture matches V3.1, so the same frame-count guidance applies: more frames give the temporal-physio model more signal. Moveris ships `mixed-90-v3_1_1` as the recommended configuration. !!! info "V3.1.1 vs V3.1" V3.1.1 is the recommended path for new integrations. Pin an explicit alias (`mixed-30-v3_1_1`) and migrate from `mixed-N-v3` or `mixed-N-v3_1` when your deployment supports V3.1.1. See [Model Versioning & Frames](versioning-and-frames.md). ## When to Use Each **Fast** — Users are impatient, risk is low, or you're re-verifying someone already trusted. **Balanced** — Standard identity verification, account creation, financial services. **Thorough** — A single false accept would be costly. Users will tolerate a longer check. **Extended** — Compliance-heavy flows, escalation when Thorough is borderline, or when regulators expect longer temporal coverage (~3 seconds). **Maximum** — Highest scrutiny scenarios: regulatory edge cases, high-value transactions, or final-level escalation when you need maximum temporal redundancy (~4 seconds). ## Escalation Pattern You don't have to pick just one. Use **Fast** by default and escalate when needed: ``` User submits → Fast (mixed-10-v2 or mixed-10-v3_1_1) → High confidence → Done → Borderline → Balanced retry (mixed-30-v2 or mixed-30-v3_1_1) → Still borderline → Thorough (mixed-60-v2, mixed-60-v3, or mixed-60-v3_1_1) → Escalation → Extended / Maximum (mixed-90-v2, mixed-120-v2, mixed-90-v3_1_1) ``` ## How Frames Affect Results More frames give the model more temporal signal to analyze — more micro-expressions, more biological coherence data across time. All v2 models achieve strong accuracy (94–96% balanced), so the primary tradeoff is latency vs. temporal redundancy rather than a large accuracy gap. All models use the same API endpoints. To select a model, pass the model ID in your request: ```json { "session_id": "...", "model": "mixed-30-v2", "frames": [...] } ``` !!! note "Frames minimum (recommended exactly)" The API requires at least the number of frames the model expects. `mixed-10-v2` expects 10 frames, `mixed-30-v2` expects 30, `mixed-60-v2` expects 60, and so on. For predictable latency, send exactly the required number. ## Deprecated Models The legacy mixed models (`mixed-10`, `mixed-30`, `mixed-60`, `mixed-90`, `mixed-120`, `mixed-150`, `mixed-250`) are deprecated. Migrate to the corresponding `mixed-N-v2` variants (e.g. `mixed-10` → `mixed-10-v2`). See [Model Versioning & Frames Parameters](versioning-and-frames.md) for alias behavior, version pinning, and the exact frame rules per endpoint. ======================================================================== Source: models/versioning-and-frames.md URL: https://documentation.moveris.com/models/versioning-and-frames/ ======================================================================== # Model Versioning & Frames Parameters How model aliases work, how to pin versions, and how to send the right frames/crops for each model. !!! info "In plain terms" Choose the correct `model` alias and send enough `frames`/`crops`. To avoid surprises, use version-suffixed aliases (`-v2`) and migrate when the model is marked as `deprecated`. ## Two ways to select a model The API supports two request flows for model selection. Use one or the other — when the v2 header is present, the `model` body field is ignored. ### Quick reference: v1 vs v2 parameters
| Flow | Request header | Body parameter | Required | Example | |------|----------------|----------------|----------|---------| | **v1** | *(none)* | `model` | No (default: `"10"`) | `model: "mixed-30-v2"` | | **v2** | `X-Model-Version` | `frame_count` | Both together | `X-Model-Version: latest` + `frame_count: 30` | - **v1:** `model` — Alias string (e.g. `"mixed-10-v2"`, `"mixed-30-v2"`, `"mixed-30-v3_1"`, `"mixed-30-v3_1_1"`, `"10"`). See [common aliases](#common-aliases) below. - **v2:** `X-Model-Version` — Version alias (`latest`, `v1`, `v2`, `v3`, `v3_1`, `v3_1_1`, `fast`). `frame_count` — One of `10`, `30`, `60`, `90`, `120`. The API resolves to the concrete model (e.g. `latest` + `30` → `mixed-30-v2`; `v3_1_1` + `30` → `mixed-30-v3_1_1`). | Client | Header | Body | Behavior | |--------|--------|------|----------| | v1 | — | `model: "mixed-30-v2"` | Unchanged; `model` used directly | | v2 | `X-Model-Version: latest` | `frame_count: 30` | Resolves to `mixed-30-v2` | | v2 | `X-Model-Version: v3_1` | `frame_count: 30` | Resolves to `mixed-30-v3_1` | | v2 | `X-Model-Version: v3_1_1` | `frame_count: 30` | Resolves to `mixed-30-v3_1_1` | #### Version aliases for `X-Model-Version`
| Version alias | Resolves to | Valid `frame_count` values | |---|---|---| | `latest` / `v2` | Mixed V2 (`mixed-N-v2`) | 10, 30, 60, 90, 120 | | `v3` | Mixed V3 (`mixed-N-v3`) | 10, 30, 60 | | `v3_1` | Mixed V3.1 (`mixed-N-v3_1`) | 10, 30, 60, 90 | | `v3_1_1` | Mixed V3.1.1 (`mixed-N-v3_1_1`) | 10, 30, 60, 90, 120 | | `fast` | Fast anti-spoofing model | 10 | | `v1` | Legacy spatial model (deprecated) | — | !!! warning "frame_count must match the version" A `frame_count` with no model for that version returns `400` (e.g. `v3` + `120`, or `v3_1` + `120`). Pick a `frame_count` listed above for your chosen version, or send the explicit alias in the `model` body field instead. Example (v2 flow): ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "frame_count": 30, "source": "live", "frames": [ ... ] } ``` Header: `X-Model-Version: latest` ### Response headers All responses include `X-Moveris-Model-Resolved` with the actual model ID used. When the resolved model is deprecated, responses also include: - `Deprecation: true` - `Sunset: ` - `X-Moveris-Deprecated-Model: ` - `X-Moveris-Suggested-Model: ` ## Model aliases (behavior) The `model` field is an alias that selects the server inference configuration (including the minimum required frames and the model type). ### Common aliases | Alias | What it does | Frame requirement | |---|---|---| | `10` | Fast anti-spoofing model (10 frames) | 10 | | `50` | Standard 72-feature spatial model (50 frames) | 50 | | `250` | High-security (mixed) spatial model (250 frames) | 250 | | `mixed-N` | Legacy mixed models (deprecated) | N | | `mixed-N-v2` | Recommended mixed v2 models | N | | `mixed-N-v3` | Mixed V3 models (next generation) | N | | `mixed-N-v3_1` | Mixed V3.1 models | N | | `mixed-N-v3_1_1` | Mixed V3.1.1 models (latest generation) | N | | `hybrid-v2-N` | Hybrid v2 models (require `fps`) | N | ### What “alias” means - The `model` you send must be a valid alias (the server validates it). - The alias determines the `frames_required` (minimum) that the server uses to validate the request. - For hybrids (`hybrid-v2-*`), the server also uses `fps` to extract consistent temporal signals. ### Where to see which models are available - The models registry `GET /api/v1/models` returns the list of aliases with `min_frames` and the `deprecated` flag. - The React SDK exposes this information via the `useModels()` hook (that’s why you see `activeModels` and `deprecatedModels`). ## How the API uses `frames` (batch endpoints) ### `POST /api/v1/fast-check` (`frames`) For `fast-check`, the server: 1. Checks that you send enough `frames` for the model. 2. Runs inference using the decodable frames included in the payload. **Frame count validation** - If you send fewer than `frames_required`, the API returns a structured error (typically code `insufficient_frames` inside the `errors` array of the [standard envelope](../api-reference/errors.md#standard-response-envelope)). - If you send more than `frames_required`, the API may process extra frames (no strict max is documented); this can increase latency. - Recommendation: send exactly `frames_required` for consistent latency and user experience. **`index` validation** - Each frame includes an `index` (0-based). - In `fast-check`, duplicate `index` values are rejected (validation fails). - The API sorts frames by `index` before processing. #### Hybrid models (`hybrid-v2-*`) and `fps` If you use a `hybrid-v2-*` model, the payload includes `fps` (frames per second) so temporal signal extraction matches your capture. - `fps` validates a range of `0 < fps <= 120`. - For non-hybrid models, `fps` does not change model selection; it is still validated by the request schema. ### `POST /api/v1/fast-check-crops` (`crops`) For `fast-check-crops`, the same rule applies: - With fewer than `frames_required` crops: same structured error pattern (`insufficient_frames` in `errors`, wrapped in the standard envelope). - With more than `frames_required` crops: the API may process additional crops (possible latency increase). - Recommendation: send exactly `frames_required` crops. **`index` validation** - Each crop includes an `index` (0-based). - In `fast-check-crops`, the API sorts crops by `index` before processing. ## `fast-check-stream`: strict indices In `POST /api/v1/fast-check-stream`, not only the count matters: the server validates the index of each frame against `frames_required`. - `frame.index` must be within `0..(frames_required - 1)`. - If you send a `frame.index` greater than or equal to `frames_required`, the API rejects the request with a `400` (detail: “exceeds maximum … for model …”). - Duplicating a `frame.index` may be idempotent in the buffer (it does not increment the counter), but the correct flow is to cover all indices from `0` to `N-1`. ## Version Pinning Version pinning is done by explicitly choosing the model alias you want. In practice, that means: 1. Use versioned aliases when available (for example, `mixed-30-v2` instead of `mixed-30`). 2. Avoid aliases marked as `deprecated` in the models registry. ### Examples - Recommended pin: `model: "mixed-30-v2"` (V2) or `model: "mixed-30-v3_1_1"` (V3.1.1, latest generation). - Migration: `model: "mixed-30"` (deprecated) -> `model: "mixed-30-v2"` or `model: "mixed-30-v3_1_1"`. - V3 / V3.1 to V3.1.1: replace `mixed-N-v3` or `mixed-N-v3_1` with `mixed-N-v3_1_1` when your deployment supports V3.1.1 checkpoints. ### Note about the alias `10` The alias `10` selects the server’s fast anti-spoofing model, and the implementation may vary depending on internal configuration (for example, the anti-spoofing version used in the deployment). If you need a strict “v1 vs v2” guarantee for the fast model, coordinate with the Moveris team—there is no additional pinning parameter for `10` on the client side. ## Deprecation lifecycle Moveris marks models as `deprecated` in the models registry. The recommended lifecycle policy is: - **Active** (`deprecated: false`): use as the default. - **Deprecated** (`deprecated: true`): keep compatibility, but migrate as soon as possible. - **Removed**: a future phase where a deprecated model may stop being available. The API and SDK expose that flag: - `GET /api/v1/models` includes `deprecated` per alias. - `useModels()` separates `activeModels` and `deprecatedModels`. ## Migration guide (when deprecations & pinning are in place) ### 1) Migrate `mixed-N` -> `mixed-N-v2` 1. Replace the `model` value in your payload: - from `mixed-30` -> to `mixed-30-v2` 2. Adjust your frame validation logic using the registry’s `min_frames` (in these cases it is often the same `N`, but the registry is the source of truth). Example (batch payload): ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-30-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." } ] } ``` ### 2) Migrate your model selector (UI / backend) If your integration today “shows all models”, switch to: - Use `activeModels` (non-deprecated) as the primary option. - Treat `deprecatedModels` as candidates only if you cannot migrate yet (and show a warning). If you use the `useModels()` hook: - The hook already provides `activeModels` and `deprecatedModels`. - Show `deprecatedModels` only as a fallback and plan a migration. ### 3) Ensure correct frame sending - Batch (`fast-check` / `fast-check-crops`): send at least `frames_required` and (recommended) exactly `frames_required`. - Stream (`fast-check-stream`): send frames with `frame.index` in `0..N-1` for your model. - Hybrids (`hybrid-v2-*`): provide real `fps` (0 < `fps` <= 120) for consistent capture. ## Quick checklist - Choose `model` using versioned aliases (`-v2`) when available. - Do not use deprecated models as the default. - Validate `frames_required` against the models registry before capturing. - Keep frame count and frame indices consistent with the endpoint (batch vs stream). ======================================================================== Source: models/fast.md URL: https://documentation.moveris.com/models/fast/ ======================================================================== # Fast — mixed-10-v2 The fastest model. Analyzes **10 frames** (0.3 seconds of video) for the lowest possible latency. ## At a Glance
Model IDmixed-10-v2
Frames required10
Capture time~0.3 seconds at 30 FPS
Avg response time~1s
Security levelStrong
## When to Use - **High-volume onboarding** where drop-off from wait time is a concern - **Repeat verification** (e.g., re-auth for returning users who are already trusted) - **Mobile-first flows** where users expect instant results - **Low-risk transactions** where speed matters more than maximum security ## Performance Based on evaluation across 1,960 test videos (9 attack types, held out from training):
EER4.4%
AUC0.988
Balanced accuracy95.2%
Avg response (fast-check)~1s
Avg response (fast-check-crops)~1s
### Per-Attack Detection | Attack Type | Detection Rate | |---|---| | Physical spoofing | 97.7% | | Deepfakes | 93.3% | | Screen replay | 92.6% | | Faceswap | 85.2% | !!! info "What this means" At the EER operating point, 95.6% of attacks are correctly blocked and 95.6% of legitimate users pass. With 10 frames of capture, this is the fastest path to a strong liveness decision. ## Tradeoffs - **Fastest response** — minimal wait time for users - **Strong across all attack types** — 93%+ detection for deepfakes, physical spoofing, and screen replay - **Faceswap is the hardest category** — 85% detection; consider escalating borderline results to Balanced ## Integration ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." }, { "index": 1, "timestamp_ms": 100, "pixels": "..." }, ... ] } ``` Capture 10 frames at 30 FPS (0.3 seconds total). ======================================================================== Source: models/balanced.md URL: https://documentation.moveris.com/models/balanced/ ======================================================================== # Balanced — mixed-30-v2 The recommended default. Analyzes **30 frames** (1 second of video) for the best overall accuracy with minimal latency. ## At a Glance
Model IDmixed-30-v2
Frames required30
Capture time~1 second at 30 FPS
Avg response time~3s
Security levelStrongest
## When to Use - **Standard KYC / identity verification** — the best default for most use cases - **Account creation** where you need solid protection without excessive friction - **Financial services** where regulatory requirements demand robust liveness checks - **Any flow where 1 second of capture is acceptable** ## Performance Based on evaluation across 1,960 test videos (9 attack types, held out from training):
EER4.0%
AUC0.991
Balanced accuracy95.7%
Avg response (fast-check)~3s
### Per-Attack Detection | Attack Type | Detection Rate | |---|---| | Physical spoofing | 98.3% | | Deepfakes | 95.6% | | Screen replay | 92.6% | | Faceswap | 80.3% | ### Operating Points The tradeoff between security and user friction at different thresholds: | Max BPCER (user rejection) | APCER (attack pass-through) | |---|---| | 1% | 12.8% | | 5% | 3.7% | | 10% | 1.6% | | Max APCER (attack pass-through) | BPCER (user rejection) | |---|---| | 1% | 10.6% | | 5% | 3.1% | | 10% | 1.2% | !!! info "What this means" At the EER operating point, 96% of attacks are correctly blocked and 96% of legitimate users pass. The 30-frame model delivers the best accuracy across all variants — the recommended choice for production. ## Tradeoffs - **Best overall accuracy** — 4.0% EER and 0.991 AUC, the top performer across all variants - **Strong across all attack types** — 95%+ detection for deepfakes and physical spoofing - **Only 1 second of capture** — acceptable for virtually all verification flows - **Best calibration** — confidence scores most accurately reflect true probabilities (lowest ECE and Brier score) ## Integration ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-30-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." }, { "index": 1, "timestamp_ms": 100, "pixels": "..." }, ... ] } ``` Capture 30 frames at 30 FPS (1 second total). ======================================================================== Source: models/thorough.md URL: https://documentation.moveris.com/models/thorough/ ======================================================================== # Thorough — mixed-60-v2 Extended analysis. Analyzes **60 frames** (2 seconds of video) for additional temporal coverage. ## At a Glance
Model IDmixed-60-v2
Frames required60
Capture time~2 seconds at 30 FPS
Avg response time~5s
Security levelStrong
## When to Use - **High-security onboarding** — financial institutions, government services, healthcare - **High-value transactions** where the cost of a false accept far outweighs wait time - **Regulated industries** where maximum detection capability is required - **Escalation flows** — use as a second check when Fast or Balanced returns a borderline result ## Performance Based on evaluation across 1,960 test videos (9 attack types, held out from training):
EER4.7%
AUC0.991
Balanced accuracy95.2%
Avg response (fast-check)~5s
### Per-Attack Detection | Attack Type | Detection Rate | |---|---| | Physical spoofing | 97.7% | | Deepfakes | 94.4% | | Screen replay | 92.6% | | Faceswap | 78.7% | !!! info "What this means" At the EER operating point, 95.3% of attacks are correctly blocked and 95.3% of legitimate users pass. The 60-frame model provides additional temporal redundancy over the 30-frame variant. ## Tradeoffs - **High AUC (0.991)** — matches the Balanced model's discrimination ability - **More temporal data** — 2 seconds of video provides additional redundancy for edge cases - **Longer capture and processing** — users need to hold still for ~2 seconds - **Best used for escalation** — when a Fast or Balanced check returns a borderline result ## Additional Variants For even more temporal coverage, two additional models are available: | Model | Frames | Capture | EER | AUC | |---|---|---|---|---| | [Extended (mixed-90-v2)](extended.md) | 90 | ~3 seconds | 5.7% | 0.989 | | [Maximum (mixed-120-v2)](maximum.md) | 120 | ~4 seconds | 4.6% | 0.991 | These are suited for specialized use cases and escalation flows requiring maximum temporal redundancy. ## Integration ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-60-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." }, { "index": 1, "timestamp_ms": 100, "pixels": "..." }, ... ] } ``` Capture 60 frames at 30 FPS (2 seconds total). !!! tip "Escalation pattern" Consider using **Fast** or **Balanced** as the default, then escalating to **Thorough** for borderline results or high-risk scenarios. This gives most users a quick experience while applying maximum scrutiny where it matters. ======================================================================== Source: models/extended.md URL: https://documentation.moveris.com/models/extended/ ======================================================================== # Extended — mixed-90-v2 Extended temporal coverage. Analyzes **90 frames** (3 seconds of video) for escalation flows and compliance-heavy use cases. ## At a Glance
Model IDmixed-90-v2
Frames required90
Capture time~3 seconds at 30 FPS
Avg response time~7s
Security levelStrong
## When to Use - **Compliance-heavy flows** — regulators expect longer temporal coverage - **Escalation** — when Thorough (mixed-60-v2) returns a borderline result - **Third-level escalation** — after Fast → Balanced → Thorough - **Specialized use cases** — where 3 seconds of capture is acceptable for maximum redundancy ## Performance Based on evaluation across 1,960 test videos (9 attack types, held out from training):
EER5.7%
AUC0.989
Balanced accuracy94.3%
Avg response~7s
!!! info "What this means" The 90-frame model adds another second of temporal data over Thorough, trading some EER for redundancy. Use it when you need more coverage than 60 frames but less latency than Maximum. ## Tradeoffs - **Extended coverage** — 3 seconds of video for additional temporal signal - **Escalation option** — fits naturally after Thorough in multi-level flows - **Higher latency** — users hold still ~3 seconds; response ~7s - **Best for escalation** — not ideal as a default; use when Thorough is inconclusive ## Integration ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-90-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." }, ... ] } ``` Capture 90 frames at 30 FPS (3 seconds total). !!! tip "See [Overview](overview.md) for the full escalation pattern" Fast → Balanced → Thorough → Extended → Maximum. Use Extended when Thorough returns borderline and you need one more step before Maximum. ======================================================================== Source: models/maximum.md URL: https://documentation.moveris.com/models/maximum/ ======================================================================== # Maximum — mixed-120-v2 Maximum temporal redundancy. Analyzes **120 frames** (4 seconds of video) for the highest scrutiny scenarios and regulatory edge cases. ## At a Glance
Model IDmixed-120-v2
Frames required120
Capture time~4 seconds at 30 FPS
Avg response time~10s
Security levelMaximum
## When to Use - **Highest scrutiny** — regulatory edge cases, government services, high-value transactions - **Final escalation** — when Extended (mixed-90-v2) is still borderline - **Maximum temporal redundancy** — where 4 seconds of capture is acceptable - **Compliance mandates** — when auditors or regulators require the longest temporal window ## Performance Based on evaluation across 1,960 test videos (9 attack types, held out from training):
EER4.6%
AUC0.991
Balanced accuracy94.7%
Avg response~10s
!!! info "What this means" The 120-frame model offers the highest temporal coverage in the Mixed V2 family. Strong AUC (0.991) and balanced accuracy (94.7%) — best for final-level escalation when latency is acceptable. ## Tradeoffs - **Maximum redundancy** — 4 seconds of video provides the most temporal signal - **Strong accuracy** — 4.6% EER, 0.991 AUC (on par with Balanced and Thorough) - **Highest latency** — ~4s capture + ~10s response; users must tolerate a longer check - **Final escalation** — use as the last step when Extended is inconclusive ## Integration ```json { "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-120-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "..." }, ... ] } ``` Capture 120 frames at 30 FPS (4 seconds total). Credits: 2 per request. !!! tip "See [Overview](overview.md) for the full escalation pattern" Use Maximum when Extended returns borderline and you need the highest possible temporal coverage before making a final decision. ======================================================================== Source: best-practices/frame-capture.md URL: https://documentation.moveris.com/best-practices/frame-capture/ ======================================================================== # Frame Capture Guidelines Best practices for capturing video frames to maximize liveness detection accuracy. !!! info "In plain terms" Capture frames from the camera; the count depends on your model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). Use PNG format for best quality. Ensure good lighting, face centered, and head-and-shoulders framing. The better the capture conditions, the more accurate the result. ## Recommendations ### 1. Frame count meets model minimum The API requires at least the number of frames required by your model: 10 for mixed-10-v2, 30 for mixed-30-v2, 60 for mixed-60-v2, and so on. For predictable latency, send exactly that many. Capture at ~10 FPS. For mixed-10-v2, that's about 1 second of video. ### 2. Use PNG encoding PNG is lossless and provides better accuracy than JPEG. The payload size is slightly larger but worth the trade-off. ### 3. Good lighting Ensure the face is well-lit with even lighting. Avoid harsh shadows or backlighting. ### 4. Face centered Keep the face centered in the frame. Head and shoulders framing is ideal. ### 5. Frame size is flexible Any resolution works. The server detects and crops the face automatically. 640×480 is a good balance of quality and size. ### 6. Capture rate Aim for 10 FPS for natural signal capture. This gives the best balance of biological signal detection and capture time. ## Capture Timing
~1 second
Example: 10 frames @ 10 FPS (mixed-10-v2) !!! tip "UI Feedback" Provide clear UI feedback during capture but keep it low friction. A subtle progress indicator works better than intrusive overlays. !!! info "SDK adaptive quality gates (3.19+ / platform-aware 3.22+)" If you use `@moveris/react` `useSmartFrameCapture`, blur and brightness thresholds **adapt** to each user's camera, lighting, and **platform** (iOS, Android, HarmonyOS, desktop) instead of fixed cutoffs. You can still set `blurThreshold` and `brightnessThreshold` as **floors**. Blur rejection resets the frame buffer so V3+ models receive consecutive frames — guide users to hold still after a blur dropout. ## Camera Positioning Checklist - :white_check_mark: Frontal face position (not angled) - :white_check_mark: Good, even lighting - :white_check_mark: Head and shoulders framing - :white_check_mark: Natural distance from camera - :white_check_mark: Relatively still during capture ======================================================================== Source: best-practices/crop-requirements.md URL: https://documentation.moveris.com/best-practices/crop-requirements/ ======================================================================== # Crop Requirements Guidelines for creating properly sized face crops for the fast-check-crops endpoint. !!! info "In plain terms" When using the crops endpoint, each face image must be 224×224 pixels and include **context around the face**—hair, neck, some background. The face should fill only ~30% of the crop. Too-tight crops (face fills >50%) reduce accuracy; the API may return a warning. ## Overview The fast-check-crops endpoint requires pre-cropped face images that include significant context around the face. This allows for faster processing since the server skips face detection. ## Cropping Process
Original
Frame
Face
Detected
3x Face
Region
224×224
PNG 1. Detect the face bounding box in the original frame 2. Calculate the center of the face bounding box 3. Expand to 3× the face size (use the larger of width/height) 4. Create a square crop centered on the face 5. Resize the crop to exactly 224×224 pixels 6. Export as PNG (base64 encoded) !!! warning "Critical: Include context around the face" The crop must include significant context around the face (hair, neck, some background). If the face fills more than 50% of the crop, the model's accuracy degrades significantly. ## Correct vs Incorrect Crops

❌ Too Tight (Wrong)

  • Face fills >50% of crop
  • Little or no context visible
  • May trigger warning in response
  • Accuracy significantly degraded

✅ Correct

  • Face is ~30% of crop
  • Hair, neck, and background visible
  • Optimal context for detection
  • Maximum accuracy achieved
## Specifications | Specification | Value | |---------------|-------| | Output Size | 224 × 224 pixels (square) | | Format | PNG, base64 encoded | | Face Size | ~30% of crop area | | Expansion Factor | 3× the detected face size | ## Recommended Libraries | Platform | Library | Description | |----------|---------|-------------| | JavaScript | `@mediapipe/tasks-vision` | Browser-based face detection | | Python | `mediapipe` | Google's MediaPipe face detection | See the [JavaScript Examples](../examples/javascript.md) and [Python Examples](../examples/python.md) for complete crop implementations. ======================================================================== Source: changelog.md URL: https://documentation.moveris.com/changelog/ ======================================================================== # Changelog All notable changes to Moveris API (v2) will be documented here. !!! info "In plain terms" This page lists new features, changes, deprecations, and fixes. Check it when upgrading your integration or troubleshooting unexpected behavior. --- ## 2026 ### [2.13.0] - 2026-07-15 #### Added * **Meeting Liveness Bot — frame quality gating** — Before frames enter the accumulator, the bot runs a gate-and-reset quality pipeline (blur, brightness, and optionally face geometry / pose). A rejected frame resets that participant's buffer so the model still receives consecutive frames. The session SSE stream adds `frame-quality-rejected` (throttled to about once per second per participant) with `participantId`, `participantName`, `reason`, `framesCollected`, and `framesRequired` so M2M clients can surface interviewer guidance. See [Integration Guide — Frame quality gating](meeting-liveness-bot/integration-guide.md#frame-quality-gating) and [API Reference — Session Events](meeting-liveness-bot/api-reference.md#session-events-sse). * **Meeting Liveness Bot — background segmentation** — Optional `bgSegmentation` on `POST /api/sessions` replaces each participant's background with neutral grey before frames are sent to `fast-check`. Defaults to the deployment setting configured by Moveris. When enabled, requests include `bg_segmentation: true` in the analysis payload. See [Integration Guide — Background segmentation](meeting-liveness-bot/integration-guide.md#background-segmentation). #### Changed * **React SDK (`@moveris/react` 3.22.0, `@moveris/shared` 3.22.0)** — Adaptive blur and brightness gates are now **platform-aware**. `detectPlatform()` classifies `'ios' | 'android' | 'harmonyos' | 'desktop' | 'other'`, and `PLATFORM_BLUR_PARAMS` tunes fraction, top percentile, and window size per platform (for example Android uses a more lenient blur curve than iOS). Existing `blurThreshold` / `brightnessThreshold` floors still apply. See [Hooks](sdk/react/hooks.md#usesmartframecapture) and [Types & Constants](sdk/shared/types.md#frame-analysis). #### Fixed * **React SDK (`@moveris/react` 3.22.4)** — `useSmartFrameCapture` adds `requireLandmarks` (default `false`). When `true`, `isDetectorReady` also waits for the FaceLandmarker before capture starts, so short `live-check` sessions do not finish with empty landmarks while the ~25MB model is still loading. Leave unset for `fast-check` / `fast-check-crops`. See [Live Check](api-reference/live-check.md) and [Hooks](sdk/react/hooks.md#usesmartframecapture). * **React SDK (`@moveris/react` 3.22.3, `@moveris/shared` 3.22.3)** — `CameraStabilizer` retries once by default after a failed 4s cold-start window (auto-exposure still converging), reducing capture starts on an unstable camera. Configurable via `StabilizerConfig.maxRetries`. * **WebRTC transport (`@moveris/webrtc` 3.22.2)** — Observer config fetch now appends `?model=` so clients route to the correct model shard. Upgrade `@moveris/webrtc` (and `@moveris/react` if you use `useWebRTCLiveness`) to 3.22.2+. * **Meeting Liveness Bot — stale session cleanup** — When a session expires, the bot now leaves the meeting (`stopBot`), broadcasts `session-status` with `fatal`, and unlocks the client form. SSE `onerror` that receives `404` for the session also marks the session fatal so the UI does not stay stuck in scanning. ### [2.12.0] - 2026-06-26 #### Added * **Mixed V3.1.1 models** — New `mixed-10-v3_1_1`, `mixed-30-v3_1_1`, `mixed-60-v3_1_1`, `mixed-90-v3_1_1`, and `mixed-120-v3_1_1` aliases. V3.1.1 is a clean retrain of the V3.1 temporal-physio family on canonical RGB inputs, with thresholds recalibrated on the real-world holdout set (equal error rate drops to roughly 5–9% on that set). Select a model with the `model` body field or with `X-Model-Version: v3_1_1` plus `frame_count` (10, 30, 60, 90, or 120). The 90-frame model (`mixed-90-v3_1_1`) is the recommended ship configuration. See [Models overview](models/overview.md#mixed-v311-models) and [Model Versioning & Frames](models/versioning-and-frames.md). * **React SDK (`@moveris/shared` / `@moveris/react` / `@moveris/react-native` / `@moveris/webrtc` 3.21.0)** — Registered the V3.1.1 models in the SDK type and config layer: `mixed-{10,30,60,90,120}-v3_1_1` added to the `FastCheckModel` union, `v3_1_1` added to `ModelVersion`, and matching `MODEL_CONFIGS` entries (per-frame `minFrames` / `recommendedFrames`). Additive; mirrors the existing V3.1 entries. * **Meeting Liveness Bot — V3.1.1 models** — The interviewer scanner and verification history now support the `mixed-*-v3_1_1` aliases, so meeting sessions can target the latest model generation. #### Changed * **Meeting Liveness Bot — H.264 video pipeline** — The bot now ingests each participant's video as an H.264 stream (the `web_4_core` meeting-provider variant) and extracts frames with FFmpeg, instead of receiving one PNG per frame. End-to-end verdict latency drops from roughly 20 seconds to about 9 seconds. Frames are now delivered at **native capture resolution** (no forced 640×480 downscale, so face proportions are preserved) and as **consecutive frames** (no frame skipping), matching how the liveness models are trained. No API changes — session endpoints, server-sent event (SSE) streams, and webhook payloads are unchanged. * **WebRTC observer reliability** — The observer deployment adds a WebSocket heartbeat and a liveness watchdog that detect dead or half-open KVS connections and recover automatically, plus separate liveness and readiness health checks so the service is not marked unhealthy while models are still warming up. No API changes for WebRTC integrators. ### [2.11.0] - 2026-06-22 #### Added * **Meeting Liveness Bot — targeted participant scanning** — `POST /api/sessions` now accepts optional `targetParticipantNames` and `excludeParticipantNames` (arrays of display names). When `targetParticipantNames` is set, the bot scans **only** matched participants; `excludeParticipantNames` skips named people (for example interviewers or hosts). Name matching is two-tier: fast fuzzy matching for clear cases, with an optional LLM confirmation step (configured by Moveris on the bot deployment) for ambiguous names. Matched participants are pinned and analyzed during active speech, so frames are captured while the subject is live on camera. The SSE stream adds `participant-stage` and `participant-matched` events for real-time UI. See [Integration Guide — Targeted participant scanning](meeting-liveness-bot/integration-guide.md#targeted-participant-scanning). #### Fixed * **WebRTC transport (`@moveris/webrtc` 3.20.2, `@moveris/react` 3.20.2)** — Fixed connection failures that prevented any WebRTC liveness session from completing. The client now reads the channel-specific signaling endpoint (`wssEndpoint`) from the observer config instead of falling back to the generic regional URL, handles the KVS `SignalingClient` SDP answer and ICE candidate event shape correctly, drains the DataChannel send buffer between chunks for larger frame counts (30+ frames), and includes a generated `session_id` in the start message so the observer returns a verdict instead of timing out. No API changes — upgrade `@moveris/webrtc` and `@moveris/react` to 3.20.2. ### [2.10.0] - 2026-06-18 #### Added * **WebRTC transport (`@moveris/webrtc` 3.20.0, `@moveris/react` 3.20.0)** — New `@moveris/webrtc` package with `WebRTCLivenessClient` for framework-agnostic liveness over a single AWS KVS WebRTC DataChannel (frames sent in 16 KB PNG chunks; verdict returned on the same channel). `@moveris/react` adds `useWebRTCLiveness` for React state management. Requires an observer deployment that exposes `/kvs/config` (separate from the standard REST base URL). See [WebRTC Quick Start](sdk/webrtc/quick-start.md) and [WebRTC Client Reference](sdk/webrtc/client.md). * **Meeting Liveness Bot — Slack notifications** — Optional Slack alerts on the bot deployment post formatted liveness verdicts (environment label, participant name, score, model, session ID). Configured by Moveris; leave disabled by default. See [Integration Guide — Slack notifications](meeting-liveness-bot/integration-guide.md#slack-notifications). #### Security * **React SDK (`@moveris/react` 3.20.0, `@moveris/webrtc` 3.20.0)** — Dependency patches for `shell-quote`, `form-data`, `vite`, and `ws`. * **Meeting Liveness Bot** — Dependency overrides updated for `react-router`, `vite`, and `ws` audit findings. ### [2.9.0] - 2026-06-11 #### Changed * **React SDK (`@moveris/react` 3.19.0, `@moveris/shared` 3.19.0)** — `useSmartFrameCapture` now uses **adaptive blur and brightness thresholds** that calibrate to each user's camera and lighting. A rolling 30-frame window derives a threshold from the top-10% mean, so low-quality cameras and dim rooms can still pass sharp, well-lit frames. The existing `blurThreshold` and `brightnessThreshold` props act as **floors** for the adaptive computation (not fixed gates). Hard floors (`MIN_BLUR_FLOOR=20`, `MIN_BRIGHTNESS_FLOOR=30`) still reject unusable frames. After five consecutive blur or brightness rejections, persistent advisory feedback takes priority over generic "hold still" copy. New exports: `computeAdaptiveBlurThreshold`, `computeAdaptiveBrightnessThreshold`, `sampleBlurVariance`, and related constants — see [Hooks](sdk/react/hooks.md) and [Types & Constants](sdk/shared/types.md). #### Fixed * **React SDK (`@moveris/react` 3.19.0)** — Blur rejection now resets the captured frame buffer (same as face-loss) so V3+ models receive fully **consecutive** frames with uniform temporal spacing. The blur gate runs pre-capture against `sampleBlurVariance` values, fixing a scale mismatch that rejected every frame when adaptive mode was enabled. #### Security * **Hosted Verification UI** — Dependency upgrades (react-router, vitest, ws, and related packages) and nginx hardening for current security advisories. ### [2.8.0] - 2026-06-08 #### Added * **v2 upload-first pipeline** — New `POST /api/v2/upload`, `POST /api/v2/fast-check`, and `POST /api/v2/live-check` endpoints. Upload frames (or a video file) during capture, then run inference by `session_id` without resending pixels. Additive to v1; existing `/api/v1/*` endpoints are unchanged. See [V2 Upload-First Pipeline](api-reference/v2-pipeline.md). * **Live Check (`POST /api/v1/live-check`)** — V3-only batch path that accepts SDK-supplied MediaPipe Face Mesh landmarks (≥468 points) per frame so the server can skip its own face-mesh pass and preserve temporal-physio signal quality. SDK: `LivenessClient.liveCheck()`, `useLiveness` with `endpoint: 'live-check'`. See [Live Check](api-reference/live-check.md). * **React SDK (`@moveris/react` 3.15.0, `@moveris/shared` 3.15.0)** — `useLivenessV2` hook and `LivenessView` `pipeline="v2"` prop for the upload-first flow (`v2Upload` → `v2FastCheck` / `v2LiveCheck`). * **Embeddable Cognito widgets (`@moveris/cognito-check` 0.3.1, `@moveris/cognito-check-react` 2.0.1)** — Added Mixed V3 (10/30/60f) and Mixed V3.1 (10/30/60/90f) model entries and the `v3` / `v3_1` model versions, so the embeddable widget can target the latest model generations. * **Meeting Liveness Bot** — Concurrent sessions (isolated per-session `FrameHandler` with scoped WebSocket routing); manual per-participant scan in the interviewer UI (explicit trigger instead of auto-accumulation); full `mixed-*-v3_1` model support in scanner and history filters. #### Changed * **React SDK (`@moveris/react` 3.14.0)** — `useSmartFrameCapture` uses `VideoFrameSync` (`requestVideoFrameCallback`) on Chrome/Safari to eliminate timer-induced duplicate and skipped frames that corrupt V3+ temporal signals. Falls back to `setInterval` on Firefox and non-browser environments. * **React SDK (`@moveris/react` 3.17.0)** — Frame encoding uses `fast-png` (level 1) instead of `canvas.toDataURL`, roughly doubling realized capture cadence (~6 fps → ~12 fps) with unchanged pixel data. New optional `brightnessThreshold` prop on `useSmartFrameCapture` overrides minimum brightness for frame acceptance. * **SDK (`@moveris/shared` 3.18.0)** — `LivenessResult` now exposes **`realScore`** (the raw `real_score` from the API, 0.0–1.0). Previously this value was dropped when building the result. Use `realScore` for decision-making; `confidence` remains reserved for future use. * **Idempotency (fast-check family)** — Session cache is now model-aware. Reusing a `session_id` with a different model returns **409** (`session_model_mismatch`) instead of replaying another model's verdict. Cached responses report the executed model. `fast-check-stream` pins the model at session creation and rejects mid-stream model switches. * **Webhook metadata** — Fast-check webhook payloads now forward client `metadata` as `tenant_metadata` consistently. #### Fixed * **`POST /api/v1/verify`** — Corrected inverted verdict and `real_score` direction for spatial-feature models; abstains instead of fabricating a verdict when both heart-rate/baseline and spatial feature extraction fail entirely. * **Hybrid models** — `hybrid-v2-*` and legacy `hybrid-50` / `hybrid-150` / `hybrid-check` requests now run the selected hybrid checkpoint instead of silently scoring with the 10-frame anti-spoofing model. * **Meeting Liveness Bot** — Fresh Moveris `session_id` on re-scan to avoid API cache hits; `bot_session_id` in request metadata for webhook clustering. #### Security * **Developer Portal API** — Backend dependencies updated to address known security advisories. ### [2.7.0] - 2026-05-14 #### Changed * **React SDK (`@moveris/react` 3.10.1)** — Canvas contexts used for capture and quality analysis pin **`colorSpace: 'srgb'`** and **`willReadFrequently: true`**, reducing pixel drift on **Display P3** / wide-gamut displays that previously skewed blur, brightness, and encoded frame data. The default full-frame capture cap moves from **640×480** to **1280×720** to align with the **V3.1** training resolution path. * **React SDK capture format (`@moveris/react` 3.10.x)** — Frame utilities emit **PNG base64 only**. The previous `'raw'` RGBA option and the `jpeg-js` encoding path were **removed** from **`captureVideoFrame`** and **`useSmartFrameCapture`**. **Breaking change for advanced integrations:** if you relied on `'raw'` output or deterministic `jpeg-js` JPEG, migrate to the returned PNG or encode JPEG yourself outside the helper. #### Fixed * **Containerized inference (MediaPipe)** — Docker images ship updated **OpenGL** libraries and a **MediaPipe** compatibility shim so face-detection workloads keep running against current upstream library expectations. ### [2.6.1] - 2026-05-11 #### Security * **Developer Portal API** — Backend dependencies updated to address known security advisories. * **Hosted Verification UI** — Dependency upgrades clear current audit findings for the hosted verification web application. * **Moveris MCP server** — Dependency overrides updated so self-hosted MCP installs pick up upstream security fixes. ### [2.6.0] - 2026-05-06 #### Changed * **React/Shared SDK (`@moveris/react` and `@moveris/shared` 3.8.6)** — Face-crop generation now matches the server/training pipeline (20% frame-based margin, bounded non-square crop, then resize to 224×224). This reduces false `fake` outcomes caused by crop mismatch in custom integrations that build their own crops with `calculateFaceCropRegion`. - **Breaking change for custom crop pipelines:** `calculateFaceCropRegion` now returns `{ x, y, width, height }` instead of `{ x, y, size }`, and `calculateAdaptiveCropMultiplier` was removed. * **React SDK capture pipeline (`@moveris/react` 3.8.2 – 3.8.5)** — Frame encoding is now deterministic across browsers (`jpeg-js` instead of `canvas.toDataURL`) and the SDK exposes an optional raw RGBA capture format on `useSmartFrameCapture` / `captureVideoFrame` for advanced integrations that need consistent pixel data and to bypass browser JPEG variance. #### Security * **Integration runtime hardening** — Additional dependency security fixes shipped across SDK and MCP surfaces, reducing vulnerability exposure for pinned and self-hosted integrator builds. ### [2.5.1] - 2026-04-23 #### Fixed * **Social login account linking (Developer Portal auth)** — When a user signs in with Google or GitHub and the email already exists, the backend now auto-links the social provider to that existing account instead of forcing password login. This removes avoidable login failures for teams using social auth. ### [2.5.0] - 2026-04-23 #### Added * **Embeddable Cognito widgets (`@moveris/cognito-check` and `@moveris/cognito-check-react` 0.1.0)** — New SDK packages provide a hosted checkbox-style verification entrypoint for teams that want a lightweight, embeddable verification trigger in web apps. * **Portal admin cache refresh action** — Admins can now trigger allowed-host cache refreshes from the backend tooling, reducing propagation delays when CORS allowlists are updated. #### Changed * **Developer Portal authentication and authorization** — Portal-facing endpoints now use JWT auth with role-based access control (RBAC) and organization scoping more consistently, improving tenant isolation for multi-org teams integrating through the portal. * **Cognito widget UX behavior** — Verification checkbox state now locks after success, applies a 30s timeout guard, and standardizes camera preview to a 4:3 aspect ratio to reduce webcam cropping issues. #### Fixed * **API key revocation handling** — Revoked API keys now raise a dedicated backend error path and return clearer auth failures for clients, making key-rotation incidents easier to diagnose. #### Security * **Dependency hardening across integration surfaces** — Additional vulnerability patches were released across MCP/server tooling and SDK build dependencies, reducing exposure for pinned deployments. ### [2.4.1] - 2026-04-22 #### Changed * **Verification UI (`0.4.0`)** — Hosted verification flow now forwards camera capability context in crop submissions, improving downstream auditability for integrators using the hosted experience. * **Developer portal backend reliability** — Admin detection listings were optimized to reduce N+1 query overhead in large datasets. This improves performance for teams reviewing verification activity. #### Security * **Runtime dependency hardening** — Security updates were shipped across SDK/Verification UI/MCP tooling, reducing known vulnerability exposure for pinned integrations. ### [2.4.0] - 2026-04-15 #### Added * **Async Video Detect idempotency** — `POST /api/v1/{tenant_slug}/video/detect` now supports the `Idempotency-Key` header. Reusing the same key with the same API key returns the original `submission_id` instead of creating duplicate async jobs, which helps integrators retry safely after network interruptions. * **React SDK (`@moveris/react` 3.7.0)** — Added `LivenessCaptureProvider` context plus brightness sampling utilities (`sampleCenterBrightness`, `sampleFaceBrightness`) for advanced custom overlays and capture-feedback UIs without prop threading. #### Changed * **React SDK (`@moveris/react` 3.6.3)** — Capture pacing can now be tuned with both `captureIntervalMs` and `minCaptureDelay`; the previous hard floor that limited effective capture rate has been removed when you set a lower delay explicitly. * **Verification UI** — Updated to SDK `@moveris/react` 3.6.3 and aligned capture throttling values for more consistent frame cadence during hosted verification sessions. * **Developer Portal integration layer** — Portal API calls now consistently target the unified `/api/v1` paths with Bearer-authenticated requests and envelope-unwrapped responses, improving compatibility with API v2 response handling in portal workflows. #### Fixed * **Async video processing (portrait videos)** — Frame extraction now correctly applies OpenCV rotation metadata for portrait MP4 uploads, preventing incorrect orientation during inference. * **React SDK (`@moveris/react` 3.6.3)** — Camera and detection loops stop as soon as frame collection enters `uploading`, avoiding unnecessary camera activity while waiting for the API response. #### Security * Dependency vulnerability updates were shipped across API, MCP, and Verification UI runtimes to reduce exposure for integrators running self-hosted or pinned builds. ### [2.3.1] - 2026-04-02 #### Fixed * **React SDK (`@moveris/react` / `@moveris/react-native` / `@moveris/shared` 3.6.2)** — When the API returns HTTP success but the JSON body has **no** `verdict` field, `LivenessClient` now maps the result to verdict **`inconclusive`** instead of throwing `LivenessApiError`. Responses that include an error or failed `success` still throw as before. #### Changed * **Developer Portal — transactional emails** — Signup, billing, and payment-related notifications use a shared base layout with refreshed copy; **`payment_failed`** template binding is corrected. ### [2.3.0] - 2026-04-02 #### Added * **Developer Portal — organization video settings** — Organization admins can set the **tenant slug** (used in `POST/GET /api/v1/{tenant_slug}/video/detect`) and an optional **video metadata schema** (JSON Schema) so `metadata` on async video submissions is validated consistently. Configure both under **Settings** in the [Developer Portal](https://developers.moveris.com/). * **Webhook delivery logs — payload echo and filters** — Delivery log API responses now include **`request_body`** (the JSON body Moveris attempted to deliver). You can filter logs by **`event_type`** (e.g. `verification.completed`, `verification.failed`) and by **`model`** (resolved model in the payload). The Portal **Webhook** / delivery views add filtering and a **detail drawer** for each attempt; event labels use the `verification.*` names. #### Changed * **React SDK (`@moveris/react` / `@moveris/react-native` / `@moveris/shared` 3.6.1)** — The “Find better lighting” advisory appears in more real-world lighting conditions (lower dynamic-range threshold), while remaining **non-blocking** — capture is not stopped. #### Security * **Moveris MCP server** — Dependency update to address a reported denial-of-service issue. ### [2.2.0] - 2026-04-01 #### Added * **`verification.failed` webhook** — In the Developer Portal you can subscribe to a second event type. Moveris sends it when ML inference or async video processing fails **after** authentication and request validation (covers `fast-check`, `fast-check-crops`, `fast-check-stream`, and tenant `video/detect`). The JSON body keeps the same top-level shape as `verification.completed` (`event`, `session_id`, `timestamp`, `data`); for failures, `data` includes `error`, `model`, `input_source`, `processing_ms`, and `frames_processed` (no verdict). The `X-Webhook-Event` header is `verification.failed`. Configure which events each webhook receives in the Portal (completed only, failed only, or both). Signing with your webhook secret works the same as for completed events. * **React SDK (`@moveris/react` / `@moveris/react-native` 3.5.0)** — Clearer camera permission denied messaging and built-in denied UI on `LivenessCamera`. #### Changed * **`@moveris/shared` (`LivenessClient`)** — Unwraps the API v2 standard JSON envelope (`data`, `success`, `message`) and maps the structured `errors` array format. Use a `@moveris/shared` release that includes this behavior together with API v2; upgrade `@moveris/react` / `@moveris/react-native` to pick up the matching dependency range. * **Default model in deployment templates** — Example and Fly/Docker configuration defaults now align on `mixed-10-v2` where a single default model alias is set (adjust `MODELS_*` / worker settings for your environment). * **Developer Portal (backend)** — Proxies to API v2 unwrap the standard response envelope (e.g. models list for the Portal UI). * **Moveris MCP server** — Consumes API v2 response envelopes; dependency updates for reported vulnerabilities (e.g. `path-to-regexp`). * **Verification UI** — End-to-end handling of API v2 standard responses. #### Fixed * **Webhook delivery logging** — Failure-path deliveries no longer hit invalid null constraints or missing session linkage when emitting `verification.failed` (delivery logs and MCP session stubs behave consistently). * **Developer Portal (web UI)** — Dependency updates (including pinned `axios`) to address npm audit findings. ### [2.1.0] - 2026-03-30 #### Added * **Standard response envelope on all endpoints** — Every JSON response is now wrapped in `{ "data": ..., "success": true/false, "message": "..." }`. Error responses include an `errors` array with error-code-keyed messages. Webhook payloads are **not** affected (they keep the `{ event, session_id, timestamp, data }` format). See [Errors](api-reference/errors.md#standard-response-envelope). * **Async tenant-scoped video detection endpoints** — New endpoints for pre-recorded video processing: * `POST /api/v1/{tenant_slug}/video/detect` to submit a video file (or URL) and get a `submission_id` * `GET /api/v1/{tenant_slug}/video/detect/{submission_id}` to poll status and retrieve results when complete Supports tenant metadata validation, tenant/org access checks, and async queue processing. * **React SDK camera capability inspection** — `@moveris/react` / `@moveris/shared` (`3.4.0`) now expose camera capability helpers (`getCameraCapabilities`, `validateCameraRequirements`, `getOptimalConstraints`) plus `useCamera` capability fields and `LivenessView` `onCapabilities` callback for device diagnostics. #### Changed * **Response format (breaking)** — All API responses now use the standard envelope. Clients must read `response.data` for the payload instead of the top-level body. Errors use `success: false` with `errors` array instead of the previous flat `{ "error": "...", "message": "..." }` format. Validation errors return `400` (previously `422`). * **React SDK capture quality signals** — Recent SDK releases improve real-time capture guidance with matrix-based roll detection and dynamic-range soft warnings ("Find better lighting"), while keeping capture non-blocking for advisory-only conditions. * **Verification UI capture flow** — Verification UI now uses crop-based submission aligned with `fast-check-crops` and supports alias-based model resolution in requests, improving compatibility with API v2 model versioning. #### Fixed * **Verification UI crop payload shape** — Crop submissions now send `{ index, pixels }` objects to match the `fast-check-crops` schema. * **Portal/API edge networking for integrators** — Upstream platform now forwards `Fly-Client-IP` through Nginx, improving real client IP visibility for integrations relying on network telemetry. ### [2.0.1] - 2026-03-23 #### Added * **React SDK: Face area quality gate** — `useSmartFrameCapture` now rejects faces that occupy less than 4% of the frame area. Helps avoid low-quality captures when the user is too far from the camera. * **React SDK: `captureIntervalMs` and `onEyeWarning`** — `useSmartFrameCapture` gains `captureIntervalMs` (default 100 ms) to tune capture rate (e.g. 50 ms for ~20 FPS). `useDetectionPipeline` gains `onEyeWarning` callback for real-time eye quality feedback ("Eyes are in shadow", "Glare detected", etc.) just before `onRestartNeeded` fires. * **MCP: `frame_count` parameter** — `verify-human-presence` tool accepts optional `frame_count` (10, 30, 60, 90, 120) to override the default derived from `risk_level`. #### Changed * **React SDK: Default endpoint** — `LivenessView` and `useLiveness` now default to `fast-check-crops` instead of `fast-check-stream`. Pass `endpoint="fast-check-stream"` to preserve previous behavior. * **MCP: Alias-based model resolution** — `verify-human-presence` tool uses API v2 alias resolution. Response `model` field now returns frame count string (e.g. `"10"`, `"30"`); new `model_version` and `frame_count` fields added. Risk levels map to `{ modelVersion: "latest", frameCount }` tuples. ### [2.0.0] - 2026-03-20 #### Added * **Model versioning (v2 flow)** — New `frame_count` body parameter and `X-Model-Version` request header for alias-based model resolution. Send `X-Model-Version: latest` (or `v1`, `v2`, `fast`, etc.) with `frame_count: 10|30|60|90|120` to resolve the concrete model. See [Model Versioning & Frames](models/versioning-and-frames.md). * **Deprecation response headers** — When using a deprecated model, responses include `Deprecation: true`, `Sunset`, `X-Moveris-Deprecated-Model`, and `X-Moveris-Suggested-Model`. All responses include `X-Moveris-Model-Resolved` with the resolved model ID. * **Billing suspension guard** — Suspended accounts receive 402 with `error: "account_suspended"` (distinct from `insufficient_credits`). Credit pre-check runs before processing; usage logs persist for audit. #### Changed * **CORS** — `X-Model-Version` header is now allowed in CORS preflight. Deprecation response headers are exposed to clients. * **Request schema** — When `X-Model-Version` header is present, the `model` body field is ignored; resolution uses `(version, frame_count)` instead. ### [1.12.0] - 2026-03-19 #### Added * **Fast Check Crops: `bg_segmentation`** — Optional request field to indicate whether background segmentation was applied to crops before sending. Stored in session metadata for A/B analytics comparing model accuracy with vs. without segmentation. ### [1.11.3] - 2026-03-17 #### Security * Backend dependency vulnerability fixes to address known security advisories. ### [1.11.2] - 2026-03-14 #### Added * React SDK: `useDetectionPipeline` hook for gaze + eye-region gating, exposing `detectionGate` and `getWarnings()` for session warnings at submit time. #### Changed * React SDK: `useSmartFrameCapture` now supports external `detectionGate` and adds `restart()` for blocking conditions (e.g. hidden/shadowed eyes). Glasses detection is non-blocking and forwarded as a warning. * Documentation: API key scopes and frame capture requirements documentation updated (including clarification for capture behavior by endpoint). ### [1.11.1] - 2026-03-12 #### Added * **AI-readable documentation** — `llms.txt` and `llms-full.txt` added for AI assistant integration (Claude Code, ChatGPT, Cursor). Enables AI tools to discover and use the API documentation during integration. * **SDK documentation updates** — Session ID (`sessionId`) prop documented for `LivenessView`, `LivenessModal`, and `useLiveness` (React and React Native). `CapturedFrame` type clarified (`timestampMs` in SDK, `timestamp_ms` in API payload). ### [1.11.0] - 2026-03-12 #### Added * **Capture warnings in fast-check responses** — Optional `warnings` field in request and response for Fast Check, Fast Check Stream, and Fast Check Crops. Frontends can report capture conditions (e.g. "Low light detected", "Face not centered"); the API echoes aggregated warnings in the response for debugging and UX improvement. #### Changed * **Basic Auth for documentation** — Optional authentication for documentation endpoints when `DOCS_BASIC_AUTH` is configured. Protects staging docs from public access. ### [1.10.0] - 2026-03-11 #### Added * **API key scopes** — API keys can be restricted by scope: `detection:write`, `detection:read`, `session:write`, `session:read`, `session:audit`, `keys:read`, `keys:write`, `usage:read`, `credits:read`, `webhooks:read`, `webhooks:write`, `hosts:read`, `hosts:write`. Create scoped keys in the Developer Portal for least-privilege access. Keys with empty scopes retain full access (backward compatible). #### Changed * Endpoints now enforce scope requirements. Requests with keys that lack the required scope return 403 with `error: "insufficient_scope"` and `required_scope` in the response. ### [1.9.1] - 2026-03-10 #### Fixed * **Mixed model credit costs** — Corrected credit deduction for mixed-v2 models (e.g. `mixed-10-v2`, `mixed-30-v2`, `mixed-90-v2`, `mixed-120-v2`). Requests using these models now deduct the correct number of credits per model config. ### [1.9.0] - 2026-03-10 #### Added * **Models registry endpoint** — GET `/api/v1/models` returns the list of available models with id, label, description, min_frames, and deprecated status. Authenticated via shared app-to-app Bearer token. Used by the Developer Portal and SDK `useModels` hook for dynamic model selection. * **React SDK `useModels` hook** — Fetch available models from the API and build dynamic model selectors with deprecated-flag support. Integrations can show model descriptions and warn when using deprecated models. ### [1.8.0] - 2026-03-10 #### Added * **Mixed V2 models** — New model family trained on 6,486 videos across 9 attack types. Includes `mixed-10-v2`, `mixed-30-v2`, `mixed-60-v2`, `mixed-90-v2`, `mixed-120-v2` with improved accuracy and per-model EER thresholds. See [Models overview](models/overview.md). #### Deprecated * **Legacy mixed models** — `mixed-10`, `mixed-30`, `mixed-60`, `mixed-90`, `mixed-120`, `mixed-150`, and `mixed-250` are deprecated. Migrate to the corresponding `mixed-N-v2` variants. ### [1.7.0] - 2026-03-06 #### Changed * **Dynamic CORS** — CORS allowed origins are now managed via the Developer Portal (AllowedHost entries) instead of a fixed configuration. Organizations can add and manage allowed hosts (e.g. for Qualtrics, Pavlovia, custom domains) without code changes. ### [1.6.0] - 2026-03-04 #### Fixed * **Documentation** — Added missing CLAUDE.md.txt download for AI integration and Claude Code workflows. ### [1.5.0] - 2026-03-04 #### Added * **Session endpoints for verification landing page** — GET `/api/v1/sessions/{session_id}` returns session context; PATCH `/api/v1/sessions/{session_id}/audit` records audit events. Enables the verification UI to display session metadata and track user interactions. * **HMAC verification token authentication** — MCP verification flows can use short-lived tokens (in URL or `X-API-Key` header) instead of API keys. Tokens are HMAC-signed server-side and include an expiration claim. #### Changed * **CORS support for verification landing page** — Added verify.moveris.com and dev.verify.moveris.com to allowed origins so the verification UI can call the API without CORS errors. #### Fixed * React SDK: Eliminated LivenessCamera flickering caused by unstable callback dependencies. * React SDK: Injectable sessionId support for liveness detection components. ### [1.4.0] - 2026-02-26 #### Added * **MCP (Model Context Protocol)** — AI agents can now verify human presence before high-stakes actions. Integrate Moveris with Cursor, Claude Desktop, ChatGPT, Microsoft Copilot, Meta AI, and other MCP hosts. Documentation includes step-by-step agent configurations. * **CORS support for Qualtrics and Pavlovia** — Embed the liveness flow in Qualtrics and Pavlovia survey subdomains without CORS errors. #### Changed * Documentation site updated with glossary improvements and MCP reference pages. ### [1.3.0] - 2026-02-24 #### Added * **Webhook delivery logs** — View delivery history and status of webhooks in the Developer Portal. Helps debug failed deliveries and monitor verification callbacks. * **MCP verification sessions** — Create and manage verification sessions for AI agents. Sessions can be tracked and cleaned up automatically. ### [1.2.0] - 2026-02-13 #### Added * **Fast Check Stream endpoint** — New endpoint for high-concurrency frame uploads. Ideal when many users verify in parallel or when you prefer streaming over batch uploads. * **Organization name and code** — API responses can include organization details for multi-tenant integrations. * **Model cards** — Public documentation for each liveness model (Fast, Balanced, Thorough) with use cases and performance characteristics. * **Documentation portal** — Central docs site at documentation.moveris.com with API reference, SDK guides, examples, and best practices. #### Changed * Improved liveness detection when using mixed frame counts across models. * React and React Native SDK documentation expanded with component usage and examples. ### [1.1.0] - 2026-02-09 #### Added * **Organization invitations** — Invite users to your organization via invitation codes in the Developer Portal. Supports email/password and social login flows. * **Streaming liveness in React** — React SDK components now support streaming options for smoother capture flows and lower latency. #### Fixed * Face-crops endpoint behavior corrected for pre-cropped image submissions. * Organization mapping and invitation code validation in the Developer Portal. --- ## How to Read This Changelog - **Added** - New features - **Changed** - Changes to existing functionality - **Deprecated** - Features that will be removed in future versions - **Removed** - Features that have been removed - **Fixed** - Bug fixes - **Security** - Security-related changes ======================================================================== Source: api-reference/health-check.md URL: https://documentation.moveris.com/api-reference/health-check/ ======================================================================== # Health Check Endpoint Check service status, loaded models, and dependency health. !!! info "In plain terms" Use this endpoint to verify the API is up and ready to accept requests. It returns the service status, API version, and whether database and Redis are healthy. No authentication required. Ideal for monitoring dashboards and uptime checks.
GET /health ## Base URL ``` https://api.moveris.com ``` ## Response Fields
| Field | Type | Description | |-------|------|-------------| | `status` | string | Service health status ("healthy") | | `version` | string | API version (e.g., "2.0.0") | | `environment` | string | "production" or "development" | | `models_loaded` | array | List of loaded model identifiers (e.g. `mixed-10-v2`, `mixed-30-v2`, `mixed-60-v2`, `mixed-90-v2`, `mixed-120-v2`; varies by deployment) | | `dependencies` | object | Status of external dependencies | ## Example ### Request ```bash curl https://api.moveris.com/health ``` ### Response All responses are wrapped in the [standard envelope](errors.md#standard-response-envelope). ```json { "data": { "status": "healthy", "version": "2.0.0", "environment": "production", "models_loaded": ["10", "50", "250", "mixed-10-v2", "mixed-30-v2", "mixed-60-v2", "mixed-90-v2", "mixed-120-v2"], "dependencies": { "database": "ok", "redis": "ok" } }, "success": true, "message": "OK" } ``` ## Usage Use this endpoint to verify the API is operational before making liveness detection requests. This is useful for monitoring and health checks in your infrastructure. For real-time system status and incident updates, visit our [Status Page](https://status.moveris.com/){ target="_blank" }. ## Related - [Video Detect (Async)](video-detect.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check (Legacy)](fast-check.md) - [Fast Check Crops](fast-check-crops.md) - [Rate Limits](rate-limits.md) - [Errors](errors.md) ======================================================================== Source: api-reference/video-detect.md URL: https://documentation.moveris.com/api-reference/video-detect/ ======================================================================== # Video Detect (Async, Tenant-Scoped) {: #video-detect-page } Submit a pre-recorded video for asynchronous liveness verification, then poll for the result. !!! info "In plain terms" Use this when you already have a full video file (for example, uploaded from a mobile app) and do not want to send frames one-by-one. You send the video once, get a `submission_id`, and check status until processing finishes. ## Endpoints | Method | Endpoint | Purpose | |---|---|---| | `POST` | `/api/v1/{tenant_slug}/video/detect` | Submit video for async processing | | `GET` | `/api/v1/{tenant_slug}/video/detect/{submission_id}` | Poll status and get final result | ## Authentication and Scopes - Header: `X-API-Key: sk-...` - Optional retry-safety header on submit: `Idempotency-Key: ` - Required scopes: - Submit: `detection:write` - Poll: `detection:read` - The API key organization must match `tenant_slug` (`tenant_mismatch` otherwise). !!! tip "Tenant slug and metadata schema" The `{tenant_slug}` path segment must match your organization’s configured **tenant slug** in the [Developer Portal](https://developers.moveris.com/) (**Settings**). If your org defines a **video metadata schema**, the optional `metadata` field is validated against it (see [Video Metadata Schema](../glossary.md#video-metadata-schema) in the Glossary). ## Submit Video `POST /api/v1/{tenant_slug}/video/detect` ### Request Content type: `multipart/form-data` Optional header for safe retries: | Header | Type | Required | Description | |---|---|---|---| | `Idempotency-Key` | string | No | Client-generated unique key for retry-safe submit requests. If you resend the same key with the same API key, the API returns the original submission instead of creating a duplicate job. |
| Field | Type | Required | Description | |---|---|---|---| | `video_file` | file | Conditional | Video file upload. Provide exactly one of `video_file` or `video_url`. | | `video_url` | string | Conditional | Presigned/public video URL. Provide exactly one of `video_file` or `video_url`. | | `model` | string | No | Model alias. Default: `mixed-10-v2`. | | `metadata` | string (JSON object) | No | Tenant metadata as JSON string. Validated against tenant schema when configured. | Allowed file extensions: `mp4`, `avi`, `mov`, `webm`, `mkv`. ### cURL Example (file upload) ```bash curl -X POST "https://api.moveris.com/api/v1/acme/video/detect" \ -H "X-API-Key: sk-your-api-key" \ -H "Idempotency-Key: onboarding-42-attempt-1" \ -F "video_file=@/path/to/selfie-video.mp4" \ -F "model=mixed-30-v2" \ -F 'metadata={"session_type":"onboarding","channel":"mobile"}' ``` ### Success Response (201) All responses are wrapped in the [standard envelope](errors.md#standard-response-envelope).
| Field | Type | Description | |---|---|---| | `submission_id` | UUID string | Unique submission ID used for polling | | `tenant` | string | Tenant slug from path | | `status` | string | Always `pending` on submit | | `model` | string | Resolved model alias used for this submission | | `message` | string | Human-readable submission status | | `tenant_metadata` | object \| null | Validated metadata echo | | `created_at` | string (ISO 8601) | Submission timestamp | ```json { "data": { "submission_id": "550e8400-e29b-41d4-a716-446655440000", "tenant": "acme", "status": "pending", "model": "mixed-30-v2", "message": "Video submitted for processing. Poll the status endpoint for results.", "tenant_metadata": { "session_type": "onboarding", "channel": "mobile" }, "created_at": "2026-03-27T12:00:00Z" }, "success": true, "message": "OK" } ``` ## Poll Submission Status `GET /api/v1/{tenant_slug}/video/detect/{submission_id}` ### cURL Example ```bash curl -X GET "https://api.moveris.com/api/v1/acme/video/detect/550e8400-e29b-41d4-a716-446655440000" \ -H "X-API-Key: sk-your-api-key" ``` ### Status Values - `pending`: queued - `processing`: running - `completed`: finished with result - `failed`: finished with error ### Completed Response (200)
| Field | Type | Description | |---|---|---| | `submission_id` | UUID string | Submission identifier | | `tenant` | string | Tenant slug | | `status` | string | `pending`, `processing`, `completed`, or `failed` | | `result` | object \| null | Unified verification result when `status=completed` | | `tenant_metadata` | object \| null | Validated metadata echo | | `message` | string \| null | Human-readable status text | | `error` | string \| null | Error when `status=failed` | | `created_at` | string (ISO 8601) | Submission creation timestamp | | `completed_at` | string (ISO 8601) \| null | Completion timestamp | ### `result` object fields
| Field | Type | Description | |---|---|---| | `verdict` | string | `live` or `fake` | | `confidence` | float | Confidence (0-1) | | `real_score` | float | Raw liveness probability (0-1) | | `score` | float | Percentage score (0-100) | | `type` | string | `VERY LOW`, `LOW`, `MEDIUM`, `HIGH`, `VERY HIGH` | | `session_id` | UUID string | Mirrors `submission_id` | | `model` | string | Model alias used | | `input_source` | string | `video_upload` | | `processing_ms` | integer | Processing time in milliseconds | | `frames_processed` | integer | Number of frames analyzed | | `tenant_metadata` | object \| null | Metadata echo for correlation | | `warning` | string \| null | Warning message if any | | `created_at` | string (ISO 8601) | Verification result generation timestamp | ```json { "data": { "submission_id": "550e8400-e29b-41d4-a716-446655440000", "tenant": "acme", "status": "completed", "result": { "verdict": "live", "confidence": 0.84, "real_score": 0.84, "score": 84.0, "type": "VERY HIGH", "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-30-v2", "input_source": "video_upload", "processing_ms": 932, "frames_processed": 30, "tenant_metadata": { "session_type": "onboarding", "channel": "mobile" }, "warning": null, "created_at": "2026-03-27T12:00:01Z" }, "tenant_metadata": { "session_type": "onboarding", "channel": "mobile" }, "message": "Processing complete.", "error": null, "created_at": "2026-03-27T12:00:00Z", "completed_at": "2026-03-27T12:00:01Z" }, "success": true, "message": "OK" } ``` ## Common Errors | HTTP | `error` | Meaning | |---|---|---| | `400` | `invalid_video_input` | Missing/duplicated video input, invalid format, or invalid model | | `400` | `invalid_metadata` | Metadata is invalid JSON or fails tenant schema | | `401` | `invalid_key` | Missing/invalid API key | | `402` | `insufficient_credits` | Not enough credits for selected model | | `403` | `tenant_mismatch` | API key does not belong to the requested tenant | | `404` | `tenant_not_found` / `submission_not_found` | Tenant or submission does not exist | | `503` | `service_unavailable` | Storage/queue/database dependency unavailable | ## Integration Notes !!! tip "Polling strategy" Poll every 1-2 seconds with exponential backoff. Stop when status is `completed` or `failed`. !!! info "Metadata" The API echoes `tenant_metadata` in both submit and status responses, so you can correlate results in your own systems. !!! tip "Idempotent retries" Use one `Idempotency-Key` per business operation (for example, one onboarding attempt). If the client times out or loses connection, retry with the same key to get the same `submission_id` and avoid duplicate async processing. !!! warning "Postman collection" Import the [Moveris API Postman collection](moveris-api-v2.postman_collection.json){ target="_blank" download } to test Video Detect (submit and poll) and the rest of the API. ## Related - [Health Check](health-check.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check (Legacy)](fast-check.md) - [Fast Check Crops](fast-check-crops.md) - [Rate Limits](rate-limits.md) - [Errors](errors.md) - [Endpoints](../getting-started/endpoints.md) ======================================================================== Source: api-reference/fast-check-stream.md URL: https://documentation.moveris.com/api-reference/fast-check-stream/ ======================================================================== # Fast Check Stream Endpoint {: #fast-check-stream-page } Liveness verification by sending **one frame per request**. You send N frames sequentially (N depends on model — e.g. 10 for `mixed-10-v2`, 30 for `mixed-30-v2`); the API buffers them and returns the verdict when the last frame arrives. Ideal when capturing frames in real time (e.g. from a camera stream). !!! info "In plain terms" Instead of sending all frames in one request, you send them one by one. Use the same `session_id` for all frames. The API buffers them and returns the live/fake verdict when the final frame (count depends on model) arrives. Best for real-time camera capture.
POST /api/v1/fast-check-stream ## Base URL ``` https://api.moveris.com ``` ## Basic Flow ``` 1. Generate a session_id (UUID) for the verification session 2. Capture N video frames (N = model's frames_required, e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) 3. Encode each frame as base64 PNG 4. Send each frame in a separate POST to /api/v1/fast-check-stream (same session_id, same model) 5. On the final frame, the API returns the verdict ("live" or "fake") with confidence score ``` !!! info "Stream vs single request" Unlike `/api/v1/fast-check` (which sends all frames in one JSON body), this endpoint receives **one frame per POST**. Use the same `session_id` and `model` for all requests. The verdict is returned only in the response to the last frame.
### Model selection: v1 vs v2 | Flow | Header | Body | What to send | |------|--------|------|--------------| | **[v1](#v1-example)** | — | `model` | `model: "mixed-30-v2"` (or `"10"`, `"mixed-10-v2"`, etc.) — same for every frame | | **[v2](#v2-example)** | `X-Model-Version` | `frame_count` | `X-Model-Version: latest` + `frame_count: 30` — same for every frame in the session | See [Model Versioning & Frames](../models/versioning-and-frames.md) for details. ## Request Headers | Header | Type | Required | Description | |--------|------|----------|-------------| | `X-Model-Version` | string | No | Version alias for v2 model resolution (e.g. `latest`, `v1`, `v2`, `fast`). When present, use with `frame_count` in body; `model` is ignored. See [Model Versioning & Frames](../models/versioning-and-frames.md). | ## Request Parameters
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `session_id` | UUID | Yes | Client-generated unique identifier; must be the same for all requests | | `model` | string | No | Model ID (e.g. `mixed-10-v2`, `mixed-30-v2`). Frame count must match the model. **Ignored when `X-Model-Version` header is present.** See [Models](../models/overview.md). | | `frame_count` | integer | No | Number of frames for v2 resolution (10, 30, 60, 90, or 120). Used with `X-Model-Version` header; must be consistent across all requests in the session. | | `source` | string | No | "media" or "live" (default: "media") | | `frame` | object | Yes | Single frame object (one per request) | | `warnings` | array | No | Optional. Per-frame capture warnings (e.g. "Low light detected"). Aggregated and echoed in final response. | ### Frame Object
| Field | Type | Required | Description | |-------|------|----------|-------------| | `index` | integer | Yes | Frame sequence number (0-based, max depends on model) | | `timestamp_ms` | float | Yes | Timestamp in milliseconds | | `pixels` | string | Yes | Base64-encoded image (PNG recommended) | ## Response Envelope All responses are wrapped in the [standard envelope](errors.md#standard-response-envelope). The `data` field contains the buffering status or verdict result. Frames 1 to N-1: buffering response. Frame N: full verdict response (N = model's frames_required). ### Buffering (frames 1 to N-1)
| Field | Type | Description | |-------|------|-------------| | `status` | string | `"buffering"` while waiting for remaining frames | | `session_id` | UUID | Echo of request session_id | | `frames_received` | integer | Number of frames received so far in this session | | `frames_required` | integer | Total frames required for the selected model | | `ttl_seconds` | integer | Remaining buffer TTL bucket for this session | | `warnings` | array \| null | Per-frame warnings if provided; null otherwise | ### Final (frame N)
| Field | Type | Description | |-------|------|-------------| | `verdict` | string | "live" or "fake" | | `confidence` | float | Reserved for future use. Functionally identical to `real_score`—use `real_score` for decision-making. | | `real_score` | float | Raw liveness probability (0.0 - 1.0). **Use this field for decision-making.** | | `score` | float | Percentage score (0 - 100) for display | | `session_id` | UUID | Echo of request session_id | | `model` | string | Model used for this request | | `processing_ms` | integer | Server processing time in milliseconds | | `frames_processed` | integer | Number of frames analyzed (matches model) | | `frames_received` | integer | Frames received in this session | | `available` | boolean | Whether the service is available | | `warning` | string \| null | Warning message if any | | `warnings` | array \| null | Aggregated capture warnings from all frames | | `error` | string \| null | Error message if any | ### Final response metadata
| Field | Type | Description | |-------|------|-------------| | `status` | string | `"complete"` when processing has finished | | `frames_required` | integer | Total frames required for this model | | `ttl_seconds` | integer | `0` after completion (buffer cleaned up) | ## Examples ### Single frame request (e.g. frame 0) — v1 flow ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check-stream" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "source": "live", "frame": { "index": 0, "timestamp_ms": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } }' ``` ### Single frame request — v2 flow (X-Model-Version + frame_count) ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check-stream" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -H "X-Model-Version: latest" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "frame_count": 10, "source": "live", "frame": { "index": 0, "timestamp_ms": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } }' ``` !!! tip "Consistency" When using v2 flow, send the same `frame_count` and `X-Model-Version` header for every frame in the session. ### Response while buffering (frames 1–9) ```json { "data": { "status": "buffering", "session_id": "550e8400-e29b-41d4-a716-446655440000", "frames_received": 1, "frames_required": 10, "ttl_seconds": 60, "warnings": null }, "success": true, "message": "OK" } ``` ### Response on 10th frame (verdict) ```json { "data": { "status": "complete", "verdict": "live", "confidence": 0.95, "real_score": 0.95, "score": 95.0, "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "processing_ms": 245, "frames_processed": 10, "frames_received": 10, "frames_required": 10, "ttl_seconds": 0, "available": true, "warning": null, "warnings": null, "error": null }, "success": true, "message": "OK" } ``` ### JavaScript: send 10 frames sequentially ```javascript // Send 10 frames sequentially (same session_id) const sessionId = crypto.randomUUID(); const frameCount = 10; // Assume getFrame(i) returns { index, timestamp_ms, pixels } from camera for (let i = 0; i < frameCount; i++) { const frame = getFrame(i); const res = await fetch('https://api.moveris.com/api/v1/fast-check-stream', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'sk-your-api-key', // Optional v2 flow: use X-Model-Version + frame_count instead of model // 'X-Model-Version': 'latest', }, body: JSON.stringify({ session_id: sessionId, model: 'mixed-10-v2', // frame_count: frameCount, // Use with X-Model-Version for v2 flow source: 'live', frame: { index: frame.index, timestamp_ms: frame.timestamp_ms, pixels: frame.pixels, }, }), }); const envelope = await res.json(); const data = envelope.data; if (data.verdict) { console.log('Verdict:', data.verdict, 'Score:', data.score); break; // last frame: verdict is ready } console.log('Buffering:', data.frames_received); } ``` !!! warning "Postman collection" Import the [Moveris API Postman collection](moveris-api-v2.postman_collection.json){ target="_blank" download } to call every endpoint, including this one. The stream requests send frames sequentially and assert `frames_received` and the final `verdict`. !!! info "AI agents" For AI agents (Cursor, Cowork), see [MCP](../mcp/overview.md) to verify human presence before high-stakes actions. ## Related - [Health Check](health-check.md) - [Video Detect (Async)](video-detect.md) - [Fast Check (Legacy)](fast-check.md) - [Fast Check Crops](fast-check-crops.md) - [Rate Limits](rate-limits.md) - [Errors](errors.md) ======================================================================== Source: api-reference/fast-check.md URL: https://documentation.moveris.com/api-reference/fast-check/ ======================================================================== # Fast Check Endpoint {: #fast-check-page } Server-side face detection for liveness verification. Analyzes video frames to determine if a face is live or spoofed. The number of frames depends on the selected model (e.g. 10 for `mixed-10-v2`, 30 for `mixed-30-v2`). !!! info "In plain terms" Send frames from a video (number depends on model — e.g. 10 frames for the fast model, 30 for the recommended balanced model). The API finds the face in each frame, analyzes it, and returns whether it's a **live** person or a **fake** (photo, video, deepfake). No client-side face detection needed—the server does it.
POST /api/v1/fast-check ## Base URL ``` https://api.moveris.com ``` !!! info "Frame requirement" The API requires at least the number of frames required by the selected model. Use 10 frames for `mixed-10-v2`, 30 for `mixed-30-v2`, 60 for `mixed-60-v2`, 90 for `mixed-90-v2`, or 120 for `mixed-120-v2`. If you send fewer, you will get `insufficient_frames`. For predictable latency, send exactly `frames_required`.
### Model selection: v1 vs v2 | Flow | Header | Body | What to send | |------|--------|------|--------------| | **[v1](#v1-example)** | — | `model` | `model: "mixed-30-v2"` (or `"10"`, `"mixed-10-v2"`, etc.) | | **[v2](#v2-example)** | `X-Model-Version` | `frame_count` | `X-Model-Version: latest` + `frame_count: 30` (10, 60, 90, or 120) | See [Model Versioning & Frames](../models/versioning-and-frames.md) for details. ## Request Headers | Header | Type | Required | Description | |--------|------|----------|-------------| | `X-Model-Version` | string | No | Version alias for v2 model resolution (e.g. `latest`, `v1`, `v2`, `fast`). When present, use with `frame_count` in body; `model` is ignored. See [Model Versioning & Frames](../models/versioning-and-frames.md). | ## Request Parameters
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `session_id` | UUID | Yes | Client-generated unique identifier | | `model` | string | No | Model ID (default: `"10"`). Recommended: `mixed-30-v2` for best accuracy. **Ignored when `X-Model-Version` header is present.** See [Models](../models/overview.md). | | `frame_count` | integer | No | Number of frames for v2 resolution (10, 30, 60, 90, or 120). Used with `X-Model-Version` header. | | `source` | string | No | "media" or "live" (default: "media") | | `frames` | array | Yes | Array of frame objects. Must include at least the model's `frames_required` (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). For predictable latency, send exactly that many. | | `warnings` | array | No | Optional. Capture warnings from frontend (e.g. "Low light detected", "Face not centered"). Duplicates are deduplicated. Echoed in response. | ### Frame Object
| Field | Type | Required | Description | |-------|------|----------|-------------| | `index` | integer | Yes | Frame sequence number (0-based) | | `timestamp_ms` | float | Yes | Timestamp in milliseconds | | `pixels` | string | Yes | Base64-encoded image (PNG recommended) | ## Response Envelope All responses are wrapped in the [standard envelope](errors.md#standard-response-envelope). The `data` field contains the verification result on success. ### `data` fields (success `200`)
| Field | Type | Description | |-------|------|-------------| | `verdict` | string | "live" or "fake" | | `confidence` | float | Reserved for future use. Functionally identical to `real_score`—use `real_score` for decision-making. | | `real_score` | float | Raw liveness probability (0.0 - 1.0). **Use this field for decision-making.** | | `score` | float | Percentage score (0 - 100) for display | | `type` | string | Risk band: `VERY LOW`, `LOW`, `MEDIUM`, `HIGH`, `VERY HIGH` | | `session_id` | UUID | Echo of request session_id | | `model` | string | Model used for this request | | `input_source` | string | How frames were submitted (`rest_frames`) | | `processing_ms` | integer | Server processing time in milliseconds | | `frames_processed` | integer | Number of frames analyzed | | `tenant_metadata` | object \| null | Tenant metadata when applicable (usually `null` on this endpoint) | | `warning` | string \| null | Warning message if any | | `created_at` | string (ISO 8601) | Timestamp when verification result was generated | ### Score Interpretation
| Score Range | Classification | Verdict | |-------------|----------------|---------| | 0 - 34 | VERY LOW | fake | | 35 - 49 | LOW | fake | | 50 - 64 | MEDIUM | fake | | 65 - 79 | HIGH | live | | 80 - 100 | VERY HIGH | live | **Threshold:** Score ≥ 65 = live, Score < 65 = fake ## Examples ### Request (v1 flow — model in body) ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." }, { "index": 1, "timestamp_ms": 100, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } ] }' ``` !!! info "Frame count" For `mixed-10-v2` send 10 frames. The example shows 2 for brevity; include frames for indices 0–9. ### Request (v2 flow — X-Model-Version + frame_count) ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -H "X-Model-Version: latest" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "frame_count": 10, "source": "live", "frames": [ { "index": 0, "timestamp_ms": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." }, { "index": 1, "timestamp_ms": 100, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } ] }' ``` !!! tip "v2 resolution" With `X-Model-Version: latest` and `frame_count: 10`, the API resolves to `mixed-10-v2`. See [Model Versioning & Frames](../models/versioning-and-frames.md). ### Success Response ```json { "data": { "verdict": "live", "confidence": 0.95, "real_score": 0.95, "score": 95.0, "type": "VERY HIGH", "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "input_source": "rest_frames", "processing_ms": 245, "frames_processed": 10, "tenant_metadata": null, "warning": null, "created_at": "2026-03-27T14:00:00Z" }, "success": true, "message": "OK" } ``` ### Error Response ```json { "data": null, "success": false, "message": "Insufficient frames. Model \"10\" requires 10 frames, received 5.", "errors": [ { "insufficient_frames": ["Insufficient frames. Model \"10\" requires 10 frames, received 5."] } ] } ``` !!! warning "Postman collection" Import the [Moveris API Postman collection](moveris-api-v2.postman_collection.json){ target="_blank" download } to test Fast Check and the rest of the API. ## Related - [Health Check](health-check.md) - [Video Detect (Async)](video-detect.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check Crops](fast-check-crops.md) - [Rate Limits](rate-limits.md) - [Errors](errors.md) ======================================================================== Source: api-reference/fast-check-crops.md URL: https://documentation.moveris.com/api-reference/fast-check-crops/ ======================================================================== # Fast Check Crops Endpoint Faster Pre-cropped face verification. Clients perform face detection locally and send pre-cropped faces, skipping server-side face detection for reduced latency. !!! info "In plain terms" If your app already detects faces (e.g., with MediaPipe), send only the cropped face images instead of full frames. This endpoint is faster because the server skips face detection. Each crop must be 224×224 pixels and include context around the face (hair, neck, background)—face should be ~30% of the image.
POST /api/v1/fast-check-crops !!! info "Frame requirement" The API requires at least the number of crops required by the selected model (e.g. 10 for `mixed-10-v2`, 30 for `mixed-30-v2`). Each crop must be 224×224 PNG. If you send fewer, you will get `insufficient_frames`. For predictable latency, send exactly `frames_required`. See [Models](../models/overview.md).
### Model selection: v1 vs v2 | Flow | Header | Body | What to send | |------|--------|------|--------------| | **[v1](#v1-example)** | — | `model` | `model: "mixed-30-v2"` (or `"10"`, `"mixed-10-v2"`, etc.) | | **[v2](#v2-example)** | `X-Model-Version` | `frame_count` | `X-Model-Version: latest` + `frame_count: 30` (10, 60, 90, or 120) | See [Model Versioning & Frames](../models/versioning-and-frames.md) for details. ## Request Headers | Header | Type | Required | Description | |--------|------|----------|-------------| | `X-Model-Version` | string | No | Version alias for v2 model resolution (e.g. `latest`, `v1`, `v2`, `fast`). When present, use with `frame_count` in body; `model` is ignored. See [Model Versioning & Frames](../models/versioning-and-frames.md). | ## Request Parameters
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `session_id` | UUID | Yes | Client-generated unique identifier | | `model` | string | No | Model ID (default: `"10"`). Recommended: `mixed-30-v2`. Crop count must meet the model minimum (`frames_required`). **Ignored when `X-Model-Version` header is present.** See [Models](../models/overview.md). | | `frame_count` | integer | No | Number of crops for v2 resolution (10, 30, 60, 90, or 120). Used with `X-Model-Version` header. | | `source` | string | No | "media" or "live" (default: "media") | | `crops` | array | Yes | Array of pre-cropped face images (224×224 PNG). Must include at least the model's `frames_required`. For predictable latency, send exactly that many. | | `bg_segmentation` | boolean | No | Optional. Indicates whether background segmentation was applied to crops before sending. Stored in session metadata for analytics. | | `warnings` | array | No | Optional. Capture warnings from frontend. Echoed in response. | ### Crop Object
| Field | Type | Required | Description | |-------|------|----------|-------------| | `index` | integer | Yes | Crop sequence number (0-based) | | `pixels` | string | Yes | Base64-encoded 224x224 PNG | ### Example requests **v1 flow (model in body):** ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check-crops" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "source": "live", "crops": [ { "index": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." }, { "index": 1, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } ], "bg_segmentation": true }' ``` **v2 flow (X-Model-Version + frame_count):** ```bash curl -X POST "https://api.moveris.com/api/v1/fast-check-crops" \ -H "Content-Type: application/json" \ -H "X-API-Key: sk-your-api-key" \ -H "X-Model-Version: latest" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000", "frame_count": 10, "source": "live", "crops": [ { "index": 0, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." }, { "index": 1, "pixels": "iVBORw0KGgoAAAANSUhEUgAA..." } ], "bg_segmentation": true }' ``` !!! info "Frame count and optional fields" For `mixed-10-v2` (or `frame_count: 10`) send 10 crops. The examples show 2 for brevity. `bg_segmentation` is optional; set to `true` if you applied background segmentation to crops before sending. ## Crop Requirements
Original
Frame
3x Face
Bounding Box
224×224
PNG 1. Detect face bounding box in original frame 2. Expand to 3× the face size (square region) 3. Resize to 224×224 pixels 4. Export as PNG !!! warning "Critical: Include context around the face" The crop must include significant context around the face (hair, neck, some background). If the face fills more than 50% of the crop, the model's accuracy degrades significantly.

❌ Too Tight (Wrong)

  • Face fills >50% of crop
  • Little or no context visible
  • May trigger warning in response
  • Accuracy significantly degraded

✅ Correct

  • Face is ~30% of crop
  • Hair, neck, and background visible
  • Optimal context for detection
  • Maximum accuracy achieved
## Response Envelope All responses are wrapped in the [standard envelope](errors.md#standard-response-envelope). The `data` field contains the verification result on success. ### `data` fields (success `200`)
| Field | Type | Description | |-------|------|-------------| | `verdict` | string | "live" or "fake" | | `confidence` | float | Reserved for future use. Functionally identical to `real_score`—use `real_score` for decision-making. | | `real_score` | float | Raw liveness probability (0.0 - 1.0). **Use this field for decision-making.** | | `score` | float | Percentage score (0 - 100) for display | | `type` | string | Risk band: `VERY LOW`, `LOW`, `MEDIUM`, `HIGH`, `VERY HIGH` | | `session_id` | UUID | Echo of request session_id | | `model` | string | Model used | | `input_source` | string | How frames were submitted (`rest_crops`) | | `processing_ms` | integer | Processing time in ms | | `frames_processed` | integer | Number of crops analyzed | | `tenant_metadata` | object \| null | Tenant metadata when applicable | | `warning` | string \| null | Warning if crops appear incorrect | | `created_at` | string (ISO 8601) | Timestamp when verification result was generated | ## Example Response with Warning ```json { "data": { "verdict": "fake", "confidence": 0.85, "real_score": 0.15, "score": 15.0, "type": "VERY LOW", "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-10-v2", "input_source": "rest_crops", "processing_ms": 420, "frames_processed": 10, "tenant_metadata": null, "warning": "Crop appears too tight (face is 72% of image). Ensure crops include adequate margin around the face (face should be ~30% of crop).", "created_at": "2026-03-27T14:00:00Z" }, "success": true, "message": "OK" } ``` ## Specifications
| Specification | Value | |---------------|-------| | Output Size | 224 × 224 pixels (square) | | Format | PNG, base64 encoded | | Face Size | ~30% of crop area | | Expansion Factor | 3× the detected face size | ## Recommended Libraries
| Platform | Library | |----------|---------| | JavaScript | `@mediapipe/tasks-vision` - Browser-based face detection | | Python | `mediapipe` - Google's MediaPipe face detection | See the [Code Examples](../examples/javascript.md) section for complete implementations. !!! warning "Postman collection" Import the [Moveris API Postman collection](moveris-api-v2.postman_collection.json){ target="_blank" download } to test Fast Check Crops and the rest of the API. ## Related - [Health Check](health-check.md) - [Video Detect (Async)](video-detect.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check (Legacy)](fast-check.md) - [Rate Limits](rate-limits.md) - [Errors](errors.md) ======================================================================== Source: api-reference/live-check.md URL: https://documentation.moveris.com/api-reference/live-check/ ======================================================================== # Live Check Endpoint {: #live-check-page } Batch liveness detection where the **client supplies MediaPipe Face Mesh landmarks** (≥468 points) per frame. The server uses those landmarks for face cropping and temporal-physio extraction instead of running its own MediaPipe pass on downsampled crops. !!! info "In plain terms" For V3 models, sending landmarks from your own face detector can improve heart-rate and blink-rhythm signals. You still send frame pixels, but each frame also includes the 468-point face mesh. Use this when you already run MediaPipe (or the SDK `useSmartFrameCapture` with face detection enabled).
POST /api/v1/live-check !!! info "v2 upload-first variant" The same landmark requirements apply to `POST /api/v2/live-check` after uploading frames (with landmarks) via `POST /api/v2/upload`. See [V2 Upload-First Pipeline](v2-pipeline.md). ## Base URL ``` https://api.moveris.com ``` ## Requirements - **V3 models only** — e.g. `mixed-10-v3`, `mixed-30-v3_1`. Other aliases return `unsupported_model` (400). - **Landmarks per frame** — ≥468 points in normalized `[0, 1]` coordinates. Accepts `[x, y, z]` arrays or `{x, y, z}` objects (MediaPipe JS format). - **Frame count** — Must match the model minimum (e.g. 10 for `mixed-10-v3_1`). ## Basic Flow ``` 1. Generate a session_id (UUID) 2. Capture N frames with MediaPipe Face Mesh landmarks attached to each frame 3. Encode pixels as base64 PNG 4. POST /api/v1/live-check with all frames in one request 5. Receive verdict ("live" or "fake") with real_score ``` ## Request Headers | Header | Type | Required | Description | |--------|------|----------|-------------| | `X-API-Key` | string | Yes | Your API key | | `X-Model-Version` | string | No | Version alias for v2 model resolution (e.g. `latest`) | ## Request body
| Field | Type | Required | Description | |-------|------|----------|-------------| | `session_id` | UUID | Yes | Unique session identifier | | `model` | string | No | V3 model alias. Ignored when `X-Model-Version` is set | | `source` | string | No | `"media"` or `"live"` (default: `"media"`) | | `fps` | float | No | Capture FPS (default: `30.0`) | | `frames` | LiveCheckFrame[] | Yes | Array of frames with pixels **and** landmarks | | `frame_count` | integer | No | For v2 resolution with `X-Model-Version` | | `warnings` | string[] | No | Client capture warnings | | `metadata` | object | No | Arbitrary metadata echoed in webhooks | ### LiveCheckFrame object
| Field | Type | Required | Description | |-------|------|----------|-------------| | `index` | integer | Yes | Frame sequence number (0-based) | | `timestamp_ms` | float | Yes | Timestamp in milliseconds | | `pixels` | string | Yes | Base64-encoded PNG | | `landmarks` | array | Yes | ≥468 landmark points — `[x, y, z]` or `{x, y, z}` per point | ## Response Same envelope and verdict fields as [Fast Check](fast-check.md): ```json { "data": { "verdict": "live", "real_score": 0.88, "score": 88.0, "confidence": 0.88, "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "mixed-30-v3_1", "processing_ms": 1240, "frames_processed": 30 }, "success": true, "message": "OK" } ``` Use `real_score` for decision-making. See [Glossary — Real Score](../glossary.md#real-score). ## SDK usage ```typescript // LivenessClient — batch live-check with landmarks on each frame const result = await client.liveCheck(frames, { sessionId: 'uuid-string', source: 'live', model: 'mixed-30-v3_1', }); // useLiveness — opt into live-check endpoint const { start, result } = useLiveness({ endpoint: 'live-check', model: 'mixed-30-v3_1', }); // useSmartFrameCapture attaches landmarks automatically when FaceLandmarker is ready ``` !!! tip "Wait for the landmarker (SDK 3.22.4+)" For custom UIs using `useSmartFrameCapture` with `live-check`, set `requireLandmarks: true` so `isDetectorReady` waits for the FaceLandmarker. Otherwise a short capture (for example 10 frames) can finish before landmarks load and every frame fails server-side face detection. See [LivenessClient](../sdk/shared/client.md#livecheckframes-options) and [React Hooks](../sdk/react/hooks.md#usesmartframecapture). ## Errors | Status | Code | When | |--------|------|------| | 400 | `unsupported_model` | Model is not a V3 alias | | 400 | `insufficient_frames` | Fewer frames than the model requires | | 409 | `session_model_mismatch` | Reused `session_id` with a different model | See [Errors](errors.md). ## Related - [V2 Upload-First Pipeline](v2-pipeline.md) — upload frames first, then `POST /api/v2/live-check` - [Fast Check](fast-check.md) — standard batch path without client landmarks - [Frame Capture best practices](../best-practices/frame-capture.md) ======================================================================== Source: api-reference/v2-pipeline.md URL: https://documentation.moveris.com/api-reference/v2-pipeline/ ======================================================================== # V2 Upload-First Pipeline {: #v2-pipeline-page } Upload frames during capture, then run inference by `session_id` without resending pixels. The v2 pipeline is **additive** — all `/api/v1/*` endpoints remain unchanged. !!! info "In plain terms" Instead of sending all frames in one big request at the end, you upload them in chunks as you capture. When enough frames are buffered server-side, you call a lightweight check endpoint that only needs the `session_id`. This reduces payload size on the final inference call and pairs well with the React SDK `useLivenessV2` hook. ## Base URL ``` https://api.moveris.com ``` ## Three-Step Flow ``` 1. Generate a session_id (UUID) for the verification session 2. POST /api/v2/upload — send frames (or a video file) in one or more requests; repeat until is_complete is true 3. POST /api/v2/fast-check OR POST /api/v2/live-check — send session_id only; server resolves frames and returns the verdict ``` !!! tip "SDK shortcut" Use `useLivenessV2` or `LivenessView` with `pipeline="v2"` — the SDK handles chunked uploads and the final check call. See [React Hooks](../sdk/react/hooks.md#uselivenessv2). ### SDK example (manual flow) ```typescript // 1. Upload frames in chunks during capture (repeat until is_complete) await client.v2Upload(frames, { sessionId, model: 'mixed-30-v3_1', source: 'live', withLandmarks: true, // required only for the live-check path }); // 2. Run inference by session_id (no frames in the body) const result = await client.v2FastCheck({ sessionId, model: 'mixed-30-v3_1' }); // or, for the V3 landmark path: // const result = await client.v2LiveCheck({ sessionId, model: 'mixed-30-v3_1' }); ``` --- ## Step 1 — Upload
POST /api/v2/upload Buffering only. Stores frames (or extracts them from an uploaded video) keyed by `session_id`. **Never runs inference.** ### Request body Provide **exactly one** of `frames` (JSON array) or `video` (multipart file).
| Field | Type | Required | Description | |-------|------|----------|-------------| | `session_id` | UUID | Yes | Same ID for all upload chunks and the final check call | | `model` | string | No | Model alias (e.g. `mixed-30-v3_1`). Ignored when `X-Model-Version` header is present | | `source` | string | No | `"media"` or `"live"` (default: `"media"`) | | `fps` | float | No | Video FPS (default: `30.0`) — required for hybrid models | | `frames` | FrameData[] | One of frames/video | Batch of frames with `index`, `timestamp_ms`, `pixels` (base64 PNG). Optional `landmarks` for the live-check path | | `video` | file | One of frames/video | Video file; server extracts frames | | `frame_count` | integer | No | For v2 model resolution with `X-Model-Version` header (10, 30, 60, 90, or 120) | | `warnings` | string[] | No | Capture warnings from the client | ### Frame object (upload) Same as [Fast Check Stream](fast-check-stream.md#frame-object), plus optional landmarks for the live-check path:
| Field | Type | Required | Description | |-------|------|----------|-------------| | `landmarks` | array | No | MediaPipe Face Mesh output — ≥468 `[x, y, z]` or `{x, y, z}` points in normalized coordinates. Required only when you plan to call `/api/v2/live-check` | ### Upload response ```json { "data": { "session_id": "550e8400-e29b-41d4-a716-446655440000", "frames_received": 10, "frames_required": 30, "is_complete": false, "ttl_seconds": 3600, "stored_durable": true }, "success": true, "message": "OK" } ``` | Field | Description | |-------|-------------| | `frames_received` | Total frames buffered for this session so far | | `frames_required` | Frames needed before inference can run | | `is_complete` | `true` when enough frames are buffered | | `ttl_seconds` | How long buffered frames remain available | | `stored_durable` | Whether frames were persisted to durable storage | --- ## Step 2 — Fast Check (v2)
POST /api/v2/fast-check Runs inference on frames previously uploaded via `/api/v2/upload`. The request carries **no frame pixels** — only session metadata. ### Request body
| Field | Type | Required | Description | |-------|------|----------|-------------| | `session_id` | UUID | Yes | Same ID used during upload | | `model` | string | No | Model alias — must match the upload session | | `source` | string | No | `"media"` or `"live"` | | `fps` | float | No | FPS used during capture | | `frame_count` | integer | No | For v2 model resolution with `X-Model-Version` | | `warnings` | string[] | No | Capture warnings | | `metadata` | object | No | Arbitrary JSON-safe metadata echoed in webhooks as `tenant_metadata` | ### Response Same verdict fields as [Fast Check](fast-check.md): `verdict`, `real_score`, `score`, `confidence`, `processing_ms`, `model`, `session_id`, and optional `warnings`. --- ## Step 2 (alternate) — Live Check (v2)
POST /api/v2/live-check Same as v2 fast-check, but requires V3 models and frames uploaded **with landmarks** during the upload step (set `withLandmarks: true` on `v2Upload`). See [Live Check](live-check.md) for landmark requirements. --- ## Model selection Same v1 vs v2 resolution as other endpoints. See [Model Versioning & Frames](../models/versioning-and-frames.md). | Flow | Header | Body | |------|--------|------| | **v1 (direct)** | — | `model: "mixed-30-v3_1"` | | **v2 (header)** | `X-Model-Version: latest` | `frame_count: 30` | --- ## Idempotency Reusing a `session_id` with a **different model** than the one that produced a cached verdict returns **409** with `session_model_mismatch`. See [Errors](errors.md#session-model-mismatch-409). --- ## Related - [Live Check](live-check.md) — V3 landmark-based path (v1 batch and v2 upload-first) - [Fast Check Stream](fast-check-stream.md) — v1 streaming alternative - [LivenessClient — v2 methods](../sdk/shared/client.md#v2-upload-first-pipeline) - [React Hooks — useLivenessV2](../sdk/react/hooks.md#uselivenessv2) ======================================================================== Source: api-reference/errors.md URL: https://documentation.moveris.com/api-reference/errors/ ======================================================================== # Error Responses Understanding and handling API errors effectively. !!! info "In plain terms" When something goes wrong, the API returns a consistent JSON envelope with `success: false`, a human-readable `message`, and an `errors` array listing error codes and descriptions. Use the error code to decide what to do (e.g., prompt for a new API key, show a "low credits" message, or retry later). ## Standard Response Envelope All API responses (success and error) use the same envelope format. ### Success (`2xx`) ```json { "data": { ... }, "success": true, "message": "OK" } ``` ### Error (`4xx` / `5xx`) ```json { "data": null, "success": false, "message": "Human-readable summary of the error", "errors": [ { "error_code": ["Detailed error message"] } ] } ```
| Field | Type | Description | |-------|------|-------------| | `data` | object \| null | Response payload on success; `null` on error | | `success` | boolean | `true` for 2xx, `false` for 4xx/5xx | | `message` | string | `"OK"` on success; human-readable error summary on failure | | `errors` | array | Error-only. Each entry maps an error code to its messages | !!! warning "Breaking change from previous format" The previous flat error format (`{ "error": "...", "message": "..." }`) has been replaced by this envelope. All endpoints now return the envelope structure. Update your error-handling code to read `success`, `message`, and `errors` instead of the old `error` field. ## HTTP Status Codes
| Status | Error Code | Description | In Plain Terms | |--------|------------|-------------|----------------| | 400 | insufficient_frames | Not enough frames provided | You sent fewer frames than the model requires. Frame count must meet the model minimum (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). | | 400 | missing_field | Required field missing | A required field (e.g. `session_id`, `frames`) is missing from the request. | | 401 | invalid_key | Invalid or missing API key | Your API key is wrong, expired, or not sent. Check the `X-API-Key` header. | | 402 | insufficient_credits | Not enough credits | Your account has run out of credits. Top up in the Developer Portal. | | 402 | account_suspended | Account suspended | Your account is suspended due to a payment issue. Update your payment method in the Developer Portal. | | 403 | insufficient_scope | API key lacks required scope | Your API key does not have permission for this operation. Create a key with the required scope in the Developer Portal. | | 400 | validation_error | Request validation failed | The request format is invalid (e.g. wrong field types, invalid UUID). Returned as `400` with field-level detail in `errors` (not `422`). | | 409 | session_model_mismatch | Session model conflict | You reused a `session_id` with a different model than the one that produced the cached verdict. Generate a new `session_id` or use the same model. | | 429 | rate_limit_exceeded | Too many requests | You've hit the request limit. Wait for `retry_after` seconds and try again. | | 500 | internal_error | Server error | Something went wrong on our side. Retry later or check the Status Page. | ## Common Errors ### Insufficient Frames (400) Returned when the number of submitted frames is less than the required minimum for the endpoint. ```json { "data": null, "success": false, "message": "Insufficient frames. Model \"10\" requires 10 frames, received 5.", "errors": [ { "insufficient_frames": ["Insufficient frames. Model \"10\" requires 10 frames, received 5."] } ] } ``` ### Session Model Mismatch (409) {: #session-model-mismatch-409 } Returned when you reuse a `session_id` that already has a cached verdict but request a **different model**. The API rejects the replay instead of returning another model's result under the new alias. ```json { "data": null, "success": false, "message": "session_id was already processed with model \"mixed-10-v3_1\"; it cannot be reused with model \"mixed-30-v3_1\". Use a new session_id.", "errors": [ { "session_model_mismatch": ["session_id was already processed with model \"mixed-10-v3_1\"; it cannot be reused with model \"mixed-30-v3_1\". Use a new session_id."] } ] } ``` For `fast-check-stream`, switching the model mid-session (after frames are buffered under another model) returns the same `session_model_mismatch` code with a streaming-specific message. !!! tip "How to avoid this" Generate a fresh `session_id` per verification attempt, or keep the same model for all requests in a session (including `fast-check-stream` frames). Cached responses report the **executed** model, not a requested alias that differed at replay time. ### Invalid API Key (401) Returned when the API key is invalid or missing. ```json { "data": null, "success": false, "message": "Not authenticated", "errors": [ { "invalid_key": ["Not authenticated"] } ] } ``` ### Insufficient Credits (402) Returned when your account doesn't have enough credits to process the request. ```json { "data": null, "success": false, "message": "Insufficient credits. Required: 1, available: 0", "errors": [ { "insufficient_credits": ["Insufficient credits. Required: 1, available: 0"] } ] } ``` ### Account Suspended (402) Returned when your account is suspended due to a payment issue (e.g. failed payment, overdue invoice). ```json { "data": null, "success": false, "message": "Your account is suspended due to a payment issue. Please update your payment method.", "errors": [ { "account_suspended": ["Your account is suspended due to a payment issue. Please update your payment method."] } ] } ``` ### Validation Error (400) Returned when the request body fails validation. The API converts 422 validation errors to 400 with field-level detail. ```json { "data": null, "success": false, "message": "session_id is required", "errors": [ { "session_id": ["session_id is required"] } ] } ``` ### Insufficient Scope (403) Returned when your API key does not have the required scope for the requested endpoint. ```json { "data": null, "success": false, "message": "API key lacks required scope: detection:write", "errors": [ { "insufficient_scope": ["API key lacks required scope: detection:write"] } ] } ``` ### Rate Limit Exceeded (429) Returned when you've exceeded the rate limit for your account. ```json { "data": null, "success": false, "message": "Rate limit exceeded. Please try again later.", "errors": [ { "rate_limit_exceeded": ["Rate limit exceeded. Please try again later."] } ] } ``` ## Handling Errors 1. Check `success` first — if `false`, the request failed 2. Read `message` for a human-readable summary 3. Iterate `errors` to find specific error codes (e.g. `insufficient_frames`, `invalid_key`) 4. Use the error code to decide your recovery action 5. For `insufficient_scope`, create a new API key with the required scope in the Developer Portal 6. For rate limits, implement exponential backoff 7. Implement retry logic for transient errors (500) 8. For persistent 500 errors, check our [Status Page](https://status.moveris.com/){ target="_blank" } for ongoing incidents ## Related - [Health Check](health-check.md) - [Video Detect (Async)](video-detect.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check (Legacy)](fast-check.md) - [Fast Check Crops](fast-check-crops.md) - [Rate Limits](rate-limits.md) ======================================================================== Source: api-reference/rate-limits.md URL: https://documentation.moveris.com/api-reference/rate-limits/ ======================================================================== # Rate Limits Understanding API rate limits and how to handle rate limiting responses. !!! info "In plain terms" The API limits how many requests you can make per minute (240 for most endpoints). If you exceed this, you get a `429` response with `retry_after` telling you how many seconds to wait. This protects the service and ensures fair usage. Contact Moveris for higher limits if needed. ## Limits by Endpoint | Endpoint | Rate Limit | |----------|------------| | `/api/v1/fast-check` | 240 requests/minute | | `/api/v1/fast-check-stream` | 240 requests/minute | | `/api/v1/fast-check-crops` | 240 requests/minute | !!! info "Higher Limits Available" If you need higher rate limits for your application, contact the Moveris team to discuss enterprise plans with custom limits. ## Rate Limit Exceeded Response When you exceed the rate limit, you'll receive a `429` response: ```json { "data": null, "success": false, "message": "Rate limit exceeded", "errors": [ { "rate_limit_exceeded": ["Rate limit exceeded"] } ] } ``` The response may also include a **`Retry-After`** HTTP header (seconds until you can retry). Prefer that header when present. ## Handling Rate Limits 1. **Read `Retry-After`** — When the server sends this header, wait that many seconds before retrying. If the body includes `errors`, treat it like other API errors (see [Errors](errors.md)). 2. **Implement exponential backoff** — Start with the `Retry-After` value (when present) and increase wait time for subsequent failures. 3. **Queue requests** — If you're making many requests, implement a queue to stay within limits. 4. **Use Fast Check for high volume** — The /fast-check endpoint has the highest rate limit (240/min) for high-volume scenarios. ## Best Practices - Monitor your request rate and stay within published limits - Use session IDs to batch frames rather than making separate requests - Cache results when appropriate to avoid duplicate requests - Check the [Status Page](https://status.moveris.com/){ target="_blank" } if you experience unexpected rate limiting or errors ## Related - [Health Check](health-check.md) - [Video Detect (Async)](video-detect.md) - [Fast Check Stream (Default)](fast-check-stream.md) - [Fast Check (Legacy)](fast-check.md) - [Fast Check Crops](fast-check-crops.md) - [Errors](errors.md) ======================================================================== Source: examples/javascript.md URL: https://documentation.moveris.com/examples/javascript/ ======================================================================== # JavaScript Examples {: .javascript-examples-page } Complete JavaScript examples for integrating Moveris API (v2). !!! info "In plain terms" Copy these code snippets to add liveness detection to your web app. They show how to capture frames from a video element, send them to the API, and display the result. Frame count depends on the model (e.g. 10 for `mixed-10-v2`, 30 for `mixed-30-v2`). Replace the placeholder API key with yours (preferably via a backend proxy). !!! info "Moveris API (v2)" These examples use Moveris API (v2) at `https://api.moveris.com` !!! tip "Model selection" Examples use the v1 flow (`model` in body). For v2 resolution, send `X-Model-Version: latest` header with `frame_count: 10|30|60|90|120` in the body. See [Model Versioning & Frames](../models/versioning-and-frames.md). ## REST API Examples === "JavaScript" ```javascript async function checkLiveness(videoElement) { const frames = []; // Capture frames at ~10 FPS (count = model min_frames, e.g. 10 for mixed-10-v2) const frameCount = 10; // Use getModels() for dynamic model selection for (let i = 0; i < frameCount; i++) { const canvas = document.createElement('canvas'); canvas.width = 640; canvas.height = 480; const ctx = canvas.getContext('2d'); ctx.drawImage(videoElement, 0, 0, 640, 480); frames.push({ index: i, timestamp_ms: performance.now(), pixels: canvas.toDataURL('image/png').split(',')[1] }); // Wait ~100ms between frames (10 FPS) await new Promise(r => setTimeout(r, 100)); } const response = await fetch('https://api.moveris.com/api/v1/fast-check', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'sk-your-api-key' }, body: JSON.stringify({ session_id: crypto.randomUUID(), source: 'live', model: 'mixed-10-v2', frames: frames }) }); const body = await response.json(); if (!body.success) { throw new Error(body.message ?? 'Request failed'); } return body.data; } ``` === "TypeScript" ```typescript interface Frame { index: number; timestamp_ms: number; pixels: string; // Base64 } interface LivenessResult { verdict: "live" | "fake"; real_score: number; score: number; session_id: string; processing_ms: number; } async function checkLiveness( frames: Frame[], sessionId: string ): Promise { const response = await fetch( 'https://api.moveris.com/api/v1/fast-check', { method: "POST", headers: { "X-API-Key": "sk-your-api-key", "Content-Type": "application/json", }, body: JSON.stringify({ session_id: sessionId, source: "live", // v1 flow: model: "mixed-10-v2", // v2 flow (alternative): // frame_count: 10, frames, }), } ); const body = await response.json(); if (!body.success) { throw new Error(body.message ?? 'Request failed'); } return body.data as LivenessResult; } // Usage const result = await checkLiveness(frames, crypto.randomUUID()); console.log(`Verdict: ${result.verdict}, Score: ${result.score}`); ``` ## With Crops (Faster) !!! info "Dependencies" This example requires the `@mediapipe/tasks-vision` package for face detection. ```javascript import { FaceDetector, FilesetResolver } from '@mediapipe/tasks-vision'; async function checkLivenessWithCrops(videoElement) { // Initialize MediaPipe Face Detector const vision = await FilesetResolver.forVisionTasks( 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm' ); const faceDetector = await FaceDetector.createFromOptions(vision, { baseOptions: { modelAssetPath: 'https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite' }, runningMode: 'VIDEO' }); const crops = []; // Capture frames (count = model min_frames, e.g. 10 for mixed-10-v2) const frameCount = 10; for (let i = 0; i < frameCount; i++) { // Capture frame const canvas = document.createElement('canvas'); canvas.width = videoElement.videoWidth; canvas.height = videoElement.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(videoElement, 0, 0); // Detect face const detections = faceDetector.detectForVideo(canvas, performance.now()); if (detections.detections.length > 0) { const face = detections.detections[0].boundingBox; // Expand to 3x face size const centerX = face.originX + face.width / 2; const centerY = face.originY + face.height / 2; const size = Math.max(face.width, face.height) * 3; // Crop and resize to 224x224 const cropCanvas = document.createElement('canvas'); cropCanvas.width = 224; cropCanvas.height = 224; const cropCtx = cropCanvas.getContext('2d'); cropCtx.drawImage( canvas, centerX - size / 2, centerY - size / 2, size, size, 0, 0, 224, 224 ); crops.push({ index: i, pixels: cropCanvas.toDataURL('image/png').split(',')[1] }); } await new Promise(r => setTimeout(r, 100)); } const response = await fetch('https://api.moveris.com/api/v1/fast-check-crops', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'sk-your-api-key' }, body: JSON.stringify({ session_id: crypto.randomUUID(), source: 'live', model: 'mixed-10-v2', crops: crops }) }); const body = await response.json(); if (!body.success) { throw new Error(body.message ?? 'Request failed'); } return body.data; } ``` ## Async video (file upload) For a pre-recorded file, submit with **`multipart/form-data`** and optional **`Idempotency-Key`** (same key + same API key returns the original submission on retry). Use your org **tenant slug** in the path. Details: [Video Detect](../api-reference/video-detect.md). ```javascript async function submitTenantVideo(file, tenantSlug, options = {}) { const { idempotencyKey, model = "mixed-30-v2" } = options; const form = new FormData(); form.append("video_file", file, file.name || "video.mp4"); form.append("model", model); const headers = { "X-API-Key": "sk-your-api-key" }; if (idempotencyKey) { headers["Idempotency-Key"] = idempotencyKey; } const res = await fetch( `https://api.moveris.com/api/v1/${tenantSlug}/video/detect`, { method: "POST", headers, body: form } ); const body = await res.json(); if (!body.success) { throw new Error(body.message ?? "Submit failed"); } return body.data; } async function pollTenantVideo(tenantSlug, submissionId) { const res = await fetch( `https://api.moveris.com/api/v1/${tenantSlug}/video/detect/${submissionId}`, { headers: { "X-API-Key": "sk-your-api-key" } } ); const body = await res.json(); if (!body.success) { throw new Error(body.message ?? "Poll failed"); } return body.data; } ``` ## Tips - Use `crypto.randomUUID()` to generate unique session IDs - PNG encoding is recommended for better accuracy - Frame count must match model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2). Capture at ~10 FPS. - Always make API calls from your server to protect your API key - Set `source: "live"` when capturing from a live camera ======================================================================== Source: examples/react.md URL: https://documentation.moveris.com/examples/react/ ======================================================================== # React Examples Everything you need to start adding human liveness verification to your React apps. Production-ready React hooks and components for integrating liveness detection. These samples walk you through the Moveris SDK (v2)—from basic setup to production-ready implementations. !!! info "In plain terms" These React hooks and components handle camera access, frame capture, and API calls. Drop them into your app to add a liveness verification flow with minimal setup. Route API calls through your backend to keep the API key secure. !!! info "Moveris API (v2)" These examples use Moveris API (v2) endpoints. The `source` field is required and should be set to `"live"` for real-time camera capture. !!! info "SDK default" The `@moveris/react` SDK defaults to `fast-check-crops`. Use `LivenessView` or `useLiveness` for the simplest integration; pass `endpoint="fast-check-stream"` to use streaming instead. !!! warning "Security Best Practice" Never expose your API key in client-side code. Always proxy requests through your backend server. Your backend must forward requests to `api.moveris.com` with your API key in the `X-API-Key` header. The SDK defaults to [fast-check-crops](../api-reference/fast-check-crops.md); use [fast-check-stream](../api-reference/fast-check-stream.md) when you prefer streaming. !!! tip "Model selection" Examples use the v1 flow (`model` in body). For v2 resolution, add `X-Model-Version: latest` header and `frame_count` in the body. See [Model Versioning & Frames](../models/versioning-and-frames.md). ## Custom Hook A reusable hook that handles video capture, frame extraction, and API calls. Use this as the foundation for your liveness verification UI. ```typescript import { useState, useRef, useCallback } from 'react'; interface Frame { index: number; timestamp_ms: number; pixels: string; } interface LivenessResult { verdict: 'live' | 'fake'; real_score: number; score: number; session_id: string; } interface UseLivenessCheckReturn { videoRef: React.RefObject; checkLiveness: () => Promise; isChecking: boolean; result: LivenessResult | null; error: string | null; } export function useLivenessCheck(): UseLivenessCheckReturn { const [isChecking, setIsChecking] = useState(false); const [result, setResult] = useState(null); const [error, setError] = useState(null); const videoRef = useRef(null); const captureFrames = useCallback(async (): Promise => { const video = videoRef.current; if (!video) throw new Error('Video ref not set'); const frames: Frame[] = []; const frameCount = 10; // mixed-10-v2; use useModels() for dynamic selection for (let i = 0; i < frameCount; i++) { const canvas = document.createElement('canvas'); canvas.width = 640; canvas.height = 480; const ctx = canvas.getContext('2d')!; ctx.drawImage(video, 0, 0, 640, 480); frames.push({ index: i, timestamp_ms: i * 100, pixels: canvas.toDataURL('image/png').split(',')[1] }); await new Promise(resolve => setTimeout(resolve, 100)); } return frames; }, []); const checkLiveness = useCallback(async () => { setIsChecking(true); setError(null); setResult(null); try { const frames = await captureFrames(); const sessionId = crypto.randomUUID(); // Proxy through your backend to api.moveris.com (one frame per request) let lastResponse: LivenessResult | null = null; for (let i = 0; i < frames.length; i++) { const response = await fetch('/api/v1/fast-check-stream', { method: 'POST', headers: { 'Content-Type': 'application/json', // v2 flow (optional): 'X-Model-Version': 'latest', }, body: JSON.stringify({ session_id: sessionId, // v1 flow: model: 'mixed-10-v2', // v2 flow (alternative): // frame_count: 10, source: 'live', // warnings: ['Low light detected'], // optional; API echoes in response frame: { index: frames[i].index, timestamp_ms: frames[i].timestamp_ms, pixels: frames[i].pixels } }) }); const envelope = await response.json(); if (!envelope.success) { throw new Error(envelope.message || 'Liveness check failed'); } const data = envelope.data; if (data?.verdict) { lastResponse = { verdict: data.verdict, real_score: data.real_score, score: data.score ?? data.real_score * 100, session_id: data.session_id }; break; } } if (lastResponse) setResult(lastResponse); else setError('No verdict received'); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setIsChecking(false); } }, [captureFrames]); return { videoRef, checkLiveness, isChecking, result, error }; } ``` !!! info "Endpoints" The SDK defaults to [fast-check-crops](../api-reference/fast-check-crops.md). This manual example uses [fast-check-stream](../api-reference/fast-check-stream.md) (one frame per request). Alternatives: - [Fast Check Crops](../api-reference/fast-check-crops.md) — default SDK endpoint, pre-cropped 224×224 faces - [Fast Check](../api-reference/fast-check.md) — send all frames in a single request ## Complete Component A full React component with camera preview, verification button, and result display. ```typescript import { useEffect } from 'react'; import { useLivenessCheck } from './useLivenessCheck'; export function LivenessCamera() { const { videoRef, checkLiveness, isChecking, result, error } = useLivenessCheck(); useEffect(() => { let stream: MediaStream | null = null; navigator.mediaDevices .getUserMedia({ video: { facingMode: 'user', width: { ideal: 640 }, height: { ideal: 480 } } }) .then((mediaStream) => { stream = mediaStream; if (videoRef.current) { videoRef.current.srcObject = stream; } }) .catch(console.error); return () => { stream?.getTracks().forEach(track => track.stop()); }; }, [videoRef]); return (