API Reference
Overview
The application exposes a small set of authenticated JSON and multipart endpoints under GET /, /live-identify, /ui, and /api/v1/*.
Unless noted otherwise, authenticated endpoints accept the custom access token in the Authorization header. The implementation accepts either:
Authorization: Bearer <token>Authorization: <token>
Endpoint Summary
| Method | URL | Auth | Notes |
|---|---|---|---|
| GET | /api/v1/health |
No | Service health |
| POST | /api/v1/auth/login |
No | Login and issue access token |
| GET | /api/v1/auth/me |
Yes | Current user info |
| GET | /api/v1/auth/users |
Yes | List users |
| POST | /api/v1/auth/users |
Yes | Create user |
| DELETE | /api/v1/auth/users/{username} |
Yes | Delete user |
| PATCH | /api/v1/auth/users/{username}/password |
Yes | Change password |
| GET | /api/v1/auth/audit |
Yes | Get audit logs (superadmin/admin only) |
| DELETE | /api/v1/auth/audit |
Yes | Clear audit logs (superadmin only) |
| POST | /api/v1/biometrics/enroll/upload |
Yes | Enroll from photo |
| DELETE | /api/v1/biometrics/enroll/{person_id} |
Yes | Delete enrollment |
| GET | /api/v1/biometrics/enrollments |
Yes | List all biometric enrollments |
| GET | /api/v1/biometrics/enrollments/{person_id} |
Yes | Get details of a specific enrollment |
| PATCH | /api/v1/biometrics/enrollments/{person_id}/status |
Yes | Toggle activation status of enrollment |
| POST | /api/v1/biometrics/identify/upload |
Yes | Identify from photo |
| POST | /api/v1/biometrics/identify/live-video/upload |
Yes | Live-video identify |
| POST | /api/v1/biometrics/recognize/live-video/upload |
Yes | Same behavior as live-video identify |
| POST | /api/v1/biometrics/verify/upload |
Yes | Verify a claimed person_id |
| POST | /api/v1/biometrics/enroll |
Yes | Hidden alias for enrollment upload |
| POST | /api/v1/biometrics/identify |
Yes | Hidden alias for live-video identify |
| GET | / |
No | Root discovery endpoint |
| GET | /live-identify |
No | 307 redirect to /ui/index.html |
Common Error Conventions
400 Bad Request: invalid image, invalid frame sequence, spoof detected, or validation failure.401 Unauthorized: missing or invalid token, or bad credentials on login.403 Forbidden: role not allowed for the requested action.404 Not Found: only used by password change when the target account does not exist.409 Conflict: duplicate enrollment or duplicate username.422 Unprocessable Entity: request body validation failure or required field missing.429 Too Many Requests: API rate limit exceeded.500 Internal Server Error: unexpected runtime failure.
Authentication
POST /api/v1/auth/login
Authenticate a user and issue a signed access token.
Request
- Method:
POST - Content-Type:
application/json
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
username |
string | Yes | Account username |
password |
string | Yes | Account password |
Example request
curl -X POST "https://YOUR_HOST/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"superadmin","password":"superadmin"}'
Success response 200
{
"access_token": "<Your Token>",
"token_type": "bearer",
"expires_at": "2026-06-03T12:34:56Z",
"role": "superadmin",
"subject": "superadmin"
}
Error responses
401:Invalid username or password.422: JSON validation failure
GET /api/v1/auth/me
Return the authenticated subject and role.
Example request
Success response 200
Error responses
401: missing, empty, invalid, or expired token
GET /api/v1/auth/users
List all user accounts. Allowed roles: superadmin, admin.
Example request
Success response 200
[
{
"username": "superadmin",
"role": "superadmin",
"created_by": "system",
"created_at": "2026-06-03T09:00:00+00:00",
"updated_at": "2026-06-03T09:00:00+00:00"
}
]
Error responses
401: invalid token403: role not permitted
POST /api/v1/auth/users
Create a user account. Allowed roles: superadmin, admin.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
username |
string | Yes | New account username |
password |
string | Yes | New account password, minimum 8 characters |
role |
string | Yes | One of admin or viewer |
Example request
curl -X POST "https://YOUR_HOST/api/v1/auth/users" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"viewer01","password":"viewerpass1","role":"viewer"}'
Success response 200
{
"username": "viewer01",
"role": "viewer",
"created_by": "superadmin",
"created_at": "2026-06-03T09:15:00+00:00",
"updated_at": "2026-06-03T09:15:00+00:00"
}
Error responses
401: invalid token403: role not permitted or superadmin creation blocked409: username already exists422: validation failure or empty username/password
DELETE /api/v1/auth/users/{username}
Delete an account. Allowed roles: superadmin, admin.
Important behavior:
- deleting your own account is forbidden
- deleting a missing account returns
deleted: falserather than a 404 - superadmin accounts cannot be deleted through the API
Example request
Success response 200
Missing user response 200
Error responses
401: invalid token403: self-delete, role mismatch, or superadmin protection
PATCH /api/v1/auth/users/{username}/password
Change a password for yourself or, subject to role rules, another account.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
new_password |
string | Yes | New password, minimum 8 characters |
current_password |
string | Conditional | Required when changing your own password |
Example request
curl -X PATCH "https://YOUR_HOST/api/v1/auth/users/viewer01/password" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"new_password":"newpass123","current_password":"viewerpass1"}'
Success response 200
{
"username": "viewer01",
"password_changed": true,
"changed_by": "viewer01",
"updated_at": "2026-06-03T09:20:00+00:00"
}
Error responses
401: invalid token403: role mismatch or incorrect current password404: user account not found422: missing or empty username/password/current_password where required500: password change succeeded but the account could not be reloaded
Audit
GET /api/v1/auth/audit
Retrieve all audit log events in descending chronological order. Allowed roles: superadmin, admin.
Example request
Success response 200
[
{
"timestamp": "2026-06-19T05:57:55.297133Z",
"event_type": "login",
"actor": "superadmin",
"resource": "superadmin",
"outcome": "failure",
"details": {
"reason": "Invalid username or password."
}
},
{
"timestamp": "2026-06-19T05:57:44.668796Z",
"event_type": "clear-audit-logs",
"actor": "superadmin",
"resource": "audit_events",
"outcome": "success",
"details": {}
}
]
Error responses
401: invalid token403: role not permitted (e.g.viewer)
DELETE /api/v1/auth/audit
Clear all persistent audit records and log the clear action. Allowed roles: superadmin only.
Example request
Success response 200
Error responses
401: invalid token403: role not permitted (e.g.admin,viewer)
Biometrics
POST /api/v1/biometrics/enroll/upload
Enroll a person from a single face photo.
Request
- Method:
POST - Content-Type:
multipart/form-data - Query string:
force_updateoptional boolean, defaultfalse
Form fields
| Name | Type | Required | Description |
|---|---|---|---|
person_id |
string | Yes | Unique identifier |
name |
string | Yes | Display name |
photo |
file | Yes | JPG or PNG face photo |
Example request
curl -X POST "https://YOUR_HOST/api/v1/biometrics/enroll/upload?force_update=false" \
-H "Authorization: Bearer $TOKEN" \
-F "person_id=EMP001" \
-F "name=Example User" \
-F "photo=@face.jpg"
Success response 200
{
"status": "enrolled",
"person_id": "EMP001",
"name": "Example User",
"enrolled_at": "2026-06-03T09:30:00+00:00"
}
Error responses
400: unsupported file type, decode failure, no face, multiple faces, or model error401: invalid token403: role not permitted409: duplicateperson_idwhenforce_update=false422: missing required form fields
DELETE /api/v1/biometrics/enroll/{person_id}
Delete a biometric enrollment.
Example request
curl -X DELETE "https://YOUR_HOST/api/v1/biometrics/enroll/EMP001" \
-H "Authorization: Bearer $TOKEN"
Success response 200
Not found behavior
Error responses
401: invalid token403: role not permitted
GET /api/v1/biometrics/enrollments
List all biometric enrollments in the database. Allowed roles: superadmin, admin.
Example request
Success response 200
[
{
"person_id": "EMP001",
"name": "Example User",
"enrolled_at": "2026-06-03T09:30:00+00:00",
"is_active": true,
"employee_id": "emp001",
"email": "user@example.com",
"phone": "+1234567890",
"department": "Engineering",
"designation": "Software Developer",
"location": "HQ",
"manager_name": "Manager Name",
"tags": ["developer", "HQ"],
"notes": "Some notes about user",
"last_updated_at": "2026-06-03T09:30:00+00:00"
}
]
Error responses
401: invalid token403: role not permitted (e.g.viewer)
GET /api/v1/biometrics/enrollments/{person_id}
Retrieve full biometric enrollment details for a specific person_id. Allowed roles: superadmin, admin.
Example request
Success response 200
{
"person_id": "EMP001",
"name": "Example User",
"enrolled_at": "2026-06-03T09:30:00+00:00",
"is_active": true,
"employee_id": "emp001",
"email": "user@example.com",
"phone": "+1234567890",
"department": "Engineering",
"designation": "Software Developer",
"location": "HQ",
"manager_name": "Manager Name",
"tags": ["developer", "HQ"],
"notes": "Some notes about user",
"last_updated_at": "2026-06-03T09:30:00+00:00"
}
Error responses
401: invalid token403: role not permitted (e.g.viewer)404: person not found
PATCH /api/v1/biometrics/enrollments/{person_id}/status
Toggle the activation status of a biometric enrollment. Deactivating a profile excludes it from face match identification/verification operations without deleting the database records. Allowed roles: superadmin, admin.
Request
- Method:
PATCH - Content-Type:
application/json
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
is_active |
boolean | Yes | Target activation status (set true for active, false for inactive) |
Example request
curl -X PATCH "https://YOUR_HOST/api/v1/biometrics/enrollments/EMP001/status" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_active": false}'
Success response 200
Error responses
400: missing or invalidis_activefield401: invalid token403: role not permitted (e.g.viewer)404: person not found
POST /api/v1/biometrics/identify/upload
Identify a person from a single face photo.
Request
- Method:
POST - Content-Type:
multipart/form-data
Form fields
| Name | Type | Required | Description |
|---|---|---|---|
photo |
file | Yes | JPG or PNG face photo |
Example request
curl -X POST "https://YOUR_HOST/api/v1/biometrics/identify/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "photo=@probe.jpg"
Success response 200
{
"matched": true,
"person_id": "EMP001",
"name": "Example User",
"confidence": 0.7821,
"match_threshold": 0.45,
"candidates_checked": 12,
"capture_mode": "photo"
}
If no enrollments exist, the response is still 200 and looks like this:
{
"matched": false,
"person_id": null,
"name": "Unknown",
"confidence": 0.0,
"match_threshold": 0.45,
"candidates_checked": 0,
"capture_mode": "photo"
}
Error responses
400: unsupported file type, decode failure, no face, multiple faces, or no face detected in the uploaded image401: invalid token403: role not permitted422: missing file
POST /api/v1/biometrics/identify/live-video/upload
Identify a person from a live frame sequence. This endpoint has the same behavior as /api/v1/biometrics/recognize/live-video/upload.
Request
- Method:
POST - Content-Type:
multipart/form-data
Form fields
| Name | Type | Required | Description |
|---|---|---|---|
frames |
repeated string fields | Yes | Base64-encoded JPEG frames, typically 10 to 30 items |
The UI captures 20 frames at about 5 fps.
Example request
curl -X POST "https://YOUR_HOST/api/v1/biometrics/identify/live-video/upload" \
-H "Authorization: Bearer $TOKEN" \
--form-string "frames=$(base64 -w0 frame_01.jpg)" \
--form-string "frames=$(base64 -w0 frame_02.jpg)"
Success response 200
{
"verdict": "live",
"matched": true,
"person_id": "EMP001",
"name": "Example User",
"confidence": 0.8012,
"liveness": {
"blink_detected": true,
"micro_movement_detected": true
}
}
If no enrollments exist, the endpoint still returns 200:
{
"verdict": "live",
"matched": false,
"person_id": null,
"name": "Unknown",
"confidence": 0.0,
"liveness": {
"blink_detected": true,
"micro_movement_detected": true
},
"message": "No enrolled persons in database."
}
If the capture fails liveness, the server returns 400 with a structured detail object:
{
"detail": {
"verdict": "spoof_detected",
"reason": "no blink detected -- please blink naturally during capture, no face movement detected -- please hold phone naturally",
"liveness": {
"blink_detected": false,
"micro_movement_detected": false
}
}
}
Error responses
400: too few frames, no face detected in the captured sequence, or spoof detected401: invalid token403: role not permitted422: missingframes
POST /api/v1/biometrics/recognize/live-video/upload
Same behavior, payload, and responses as /api/v1/biometrics/identify/live-video/upload.
POST /api/v1/biometrics/verify/upload
Verify a face against a known person_id.
Request
- Method:
POST - Content-Type:
multipart/form-data
Form fields
| Name | Type | Required | Description |
|---|---|---|---|
person_id |
string | Yes | Known enrolled person ID |
photo |
file | Yes | JPG or PNG face photo |
Example request
curl -X POST "https://YOUR_HOST/api/v1/biometrics/verify/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "person_id=EMP001" \
-F "photo=@probe.jpg"
Success response 200
{
"person_id": "EMP001",
"enrolled": true,
"matched": true,
"name": "Example User",
"confidence": 0.7815,
"match_threshold": 0.45,
"capture_mode": "photo",
"message": "person_id is enrolled and matched."
}
If the person_id is not enrolled, the endpoint still returns 200:
{
"person_id": "EMP999",
"enrolled": false,
"matched": false,
"confidence": 0.0,
"match_threshold": 0.45,
"capture_mode": "photo",
"message": "person_id is not enrolled."
}
Error responses
400: unsupported file type, decode failure, no face, multiple faces, or model error401: invalid token403: role not permitted422: missing required form fields
Hidden aliases
The following routes are implemented but excluded from the OpenAPI schema:
POST /api/v1/biometrics/enrollPOST /api/v1/biometrics/identify
Each is an alias of the corresponding upload endpoint and uses the same request and response behavior.
Utility Routes
GET /api/v1/health
Return the service health response.
Success response 200
GET /
Return a discovery payload with the service name, version, and key endpoint paths.
Success response 200
{
"service": "PowerMind VisionID",
"version": "1.1.0",
"endpoints": {
"login": "/api/v1/auth/login",
"current_user": "/api/v1/auth/me",
"enroll": "/api/v1/biometrics/enroll/upload",
"delete_enrollment": "/api/v1/biometrics/enroll/{person_id}",
"identify_photo": "/api/v1/biometrics/identify/upload",
"identify_live_video": "/api/v1/biometrics/identify/live-video/upload",
"recognize_live_video": "/api/v1/biometrics/recognize/live-video/upload",
"verify_enrollment": "/api/v1/biometrics/verify/upload",
"health": "/api/v1/health",
"metrics": "/metrics",
"ui": "/ui/index.html"
}
}
GET /live-identify
Redirect to the UI landing page.
Response
307 Temporary Redirect- Location:
/ui/index.html
Static UI
The application also serves the browser UI under /ui. The main entry point is /ui/index.html.