# 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. ### 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). --- ## 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). ### 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. ### 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. ### Float A number with a decimal part (e.g., 0.5, 3.14, -1.0). --- ## 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). ### 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 ### 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 ### 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. --- ## 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 ### 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. ### 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 ### 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 ### Verdict The API's final decision: `"live"` (real person) or `"fake"` (spoofed/not real). ### 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 ### Webhook A URL your server provides. When an event occurs (e.g., verification complete), the API sends an HTTP POST to that URL instead of you having to poll for status. *In practice:* Register a webhook URL to receive verification results as they happen. Contrast with polling, where you repeatedly ask for status. --- ## 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 } | ## 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 | !!! 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 five model variants (Mixed V2) to match different integration needs. All models use the same architecture, trained on 6,486 videos across 9 attack types — physical spoofing, deepfakes, screen replay, faceswap, and others. The difference is how many frames are analyzed, which affects latency and temporal coverage.
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`)**" It delivers the best overall accuracy (4.0% EER, 0.991 AUC) with only 1 second of capture — the right default for most integrations. ## 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) → High confidence → Done → Borderline → Balanced (mixed-30-v2) retry → Still borderline → Thorough (mixed-60-v2) final check → Escalation → Extended (mixed-90-v2) or Maximum (mixed-120-v2) ``` ## 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"`, `"10"`). See [common aliases](#common-aliases) below. - **v2:** `X-Model-Version` — Version alias (`latest`, `v1`, `v2`, `fast`, etc.). `frame_count` — One of `10`, `30`, `60`, `90`, `120`. The API resolves to the concrete model (e.g. `latest` + `30` → `mixed-30-v2`). | 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` | 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 | | `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 `error: "insufficient_frames"`. - 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: `error: "insufficient_frames"`. - 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"` (versioned alias with `-v2`). - Migration: `model: "mixed-30"` (deprecated) -> `model: "mixed-30-v2"`. ### 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. ## 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.1.0] - 2026-03-27 #### 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 * Dependency vulnerability fixes (pillow, orjson, PyJWT) to address a Pillow out-of-bounds write and an orjson recursion DoS. ### [1.11.2] - 2026-03-13 #### 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-09 #### 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-03 #### 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 signed with `VERIFICATION_TOKEN_SECRET`. #### 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-08 #### 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) 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-...` - Required scopes: - Submit: `detection:write` - Poll: `detection:read` - The API key organization must match `tenant_slug` (`tenant_mismatch` otherwise). ## Submit Video `POST /api/v1/{tenant_slug}/video/detect` ### Request Content type: `multipart/form-data`
| 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" \ -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. !!! 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 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 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/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: 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`). | | 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."] } ] } ``` ### 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: 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; } ``` ## 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 (