Lightweight Python client for Milestone XProtect API Gateway REST APIs.
- Authenticates against the built-in Identity Provider (
/API/IDP/connect/token) - Calls Configuration REST (
/API/rest/v1/...) - Convenience helpers for tasks (
?task=...), pagination, and the well-known URIs - Thin wrappers to call Events/Alarms/Bookmarks/Evidence Locks REST families (
/API/events-rest/v1,/API/alarms-rest/v1, ...)
Works against XProtect 2022 R1+ with the API Gateway enabled.
pip install -e .from xprotect import XProtectClient
# base "gateway_url" should be the /API root (scheme + host + '/API'), e.g.:
client = XProtectClient(
gateway_url="https://test-01.example.com/API",
verify_ssl=False, # True in prod!
)
client.login(username="seamrune", password="Rad23Swops#") # demo creds
# Discover useful URIs
print(client.well_known())
# List sites via Config REST
sites = client.get_sites()
print(sites)
# Cameras with pagination
for cam in client.iter_cameras(size=50, include_disabled=False):
print(cam["displayName"])
# Invoke a task (example)
# tasks = client.get_tasks("recordingServers/{id}")
# client.invoke_task("recordingServers/{id}", "HardwareScanExpress", body={"hardwareAddress": "10.0.0.10"})# Events API (generic helper)
events = client.events_rest("GET", "/events", params={"page":0, "size":50}).json()
print(events)All responses are checked for XProtect error envelopes and HTTP errors. XProtectApiError will be raised with context.
Security note: In production, always enable TLS verification, use least-privilege accounts, and store secrets safely.
from xprotect import XProtectClient, models
client = XProtectClient("https://host/API", verify_ssl=True)
client.login("user", "pass")
# Typed list of EventType
ets: list[models.EventType] = client.get_event_types()
print(ets[0].displayName)
# Send a typed detection event
evt = models.EventCreate(
type=ets[0].id,
source="cameras/{camera-guid}",
datatype="application/json",
data={"label": "person", "confidence": 0.93},
tag="ai:detection:person",
)
status = client.trigger_event(evt, trigger_rules=True)
print("status:", status)