Python Examples¶
Complete Python examples for integrating Moveris API (v2).
In plain terms
These examples show how to send video frames from Python to the Moveris API. Use them for server-side liveness checks (e.g., processing uploaded videos) or backend proxies that receive frames from a frontend.
Moveris API (v2)
These examples use Moveris API (v2) at https://api.moveris.com
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.
REST API Example¶
import base64
import uuid
import cv2
import requests
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.moveris.com"
def check_liveness(video_path: str, model: str = "mixed-10-v2") -> dict:
"""Check liveness. Frame count must match model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2)."""
frame_count = 10 if "mixed-10" in model else (30 if "mixed-30" in model else 10)
cap = cv2.VideoCapture(video_path)
frames = []
for i in range(frame_count):
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(
f'{BASE_URL}/api/v1/fast-check',
headers={
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
# v2 flow (optional): 'X-Model-Version': 'latest'
},
json={
'session_id': str(uuid.uuid4()),
'source': 'live',
# v1 flow:
'model': model,
# v2 flow (alternative):
# 'frame_count': 10,
'frames': frames
}
)
body = response.json()
if not body.get("success", False):
raise RuntimeError(body.get("message", "Request failed"))
return body["data"]
# Usage
result = check_liveness("video.mp4")
print(f"Verdict: {result['verdict']}, Score: {result['score']}")
With Crops (Faster)¶
Dependencies
opencv-pythonrequestsmediapipe
import base64
import uuid
import cv2
import requests
import mediapipe as mp
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.moveris.com"
def check_liveness_with_crops(video_path: str) -> dict:
"""Check liveness using pre-cropped faces with MediaPipe."""
# Initialize MediaPipe Face Detection
mp_face_detection = mp.solutions.face_detection
face_detection = mp_face_detection.FaceDetection(
model_selection=0,
min_detection_confidence=0.5
)
cap = cv2.VideoCapture(video_path)
crops = []
frame_count = 10 # for mixed-10-v2; use getModels() for dynamic selection
for i in range(frame_count):
ret, frame = cap.read()
if not ret:
break
# Convert to RGB for MediaPipe
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = face_detection.process(rgb_frame)
if results.detections:
detection = results.detections[0]
bbox = detection.location_data.relative_bounding_box
h, w = frame.shape[:2]
x = int(bbox.xmin * w)
y = int(bbox.ymin * h)
face_w = int(bbox.width * w)
face_h = int(bbox.height * h)
# Calculate 3x expanded crop region
center_x = x + face_w // 2
center_y = y + face_h // 2
crop_size = max(face_w, face_h) * 3
x1 = max(0, int(center_x - crop_size // 2))
y1 = max(0, int(center_y - crop_size // 2))
x2 = min(w, int(center_x + crop_size // 2))
y2 = min(h, int(center_y + crop_size // 2))
# Crop and resize to 224x224
crop = frame[y1:y2, x1:x2]
crop = cv2.resize(crop, (224, 224))
_, png_data = cv2.imencode('.png', crop)
pixels = base64.b64encode(png_data.tobytes()).decode('utf-8')
crops.append({
'index': i,
'pixels': pixels
})
cap.release()
face_detection.close()
response = requests.post(
f'{BASE_URL}/api/v1/fast-check-crops',
headers={
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
# v2 flow (optional): 'X-Model-Version': 'latest'
},
json={
'session_id': str(uuid.uuid4()),
'source': 'live',
# v1 flow:
'model': 'mixed-10-v2',
# v2 flow (alternative):
# 'frame_count': 10,
'crops': crops,
# 'bg_segmentation': True, # Optional: set if you applied background segmentation to crops
}
)
body = response.json()
if not body.get("success", False):
raise RuntimeError(body.get("message", "Request failed"))
return body["data"]
Async video (tenant-scoped)¶
Submit a full video file once and poll for the result. Use an Idempotency-Key on submit so retries after timeouts return the same submission_id instead of duplicating jobs. Replace TENANT_SLUG with your org’s slug from the Developer Portal. Full reference: Video Detect.
import time
import uuid
from typing import Optional
import requests
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.moveris.com"
TENANT_SLUG = "acme"
VIDEO_PATH = "recording.mp4"
def submit_video(idempotency_key: Optional[str] = None) -> dict:
headers = {"X-API-Key": API_KEY}
if idempotency_key:
headers["Idempotency-Key"] = idempotency_key
with open(VIDEO_PATH, "rb") as f:
response = requests.post(
f"{BASE_URL}/api/v1/{TENANT_SLUG}/video/detect",
headers=headers,
files={"video_file": ("video.mp4", f, "video/mp4")},
data={"model": "mixed-30-v2"},
timeout=120,
)
body = response.json()
if not body.get("success", False):
raise RuntimeError(body.get("message", "Submit failed"))
return body["data"]
def poll_until_done(submission_id: str, timeout_s: float = 300.0) -> dict:
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
r = requests.get(
f"{BASE_URL}/api/v1/{TENANT_SLUG}/video/detect/{submission_id}",
headers={"X-API-Key": API_KEY},
timeout=60,
)
body = r.json()
if not body.get("success", False):
raise RuntimeError(body.get("message", "Poll failed"))
data = body["data"]
if data["status"] in ("completed", "failed"):
return data
time.sleep(1.5)
raise TimeoutError("Polling timed out")
if __name__ == "__main__":
key = str(uuid.uuid4()) # one key per logical operation; reuse on retry
submitted = submit_video(idempotency_key=key)
final = poll_until_done(submitted["submission_id"])
print(final)