Skip to content

API Reference

All endpoints are under /api/v1. Endpoints require authentication unless the route uses a documented device key or webhook secret flow.

Authentication is resolved from API keys, device keys, or route-specific secrets. Authorization uses permission patterns from config/auth.yaml.

Execution observability

Use GET /workflows/{execution_id}/detail for inspection. Use /pipeline/runs for lightweight live lists and dashboards.

MethodPathDescription
GET/workflowsList executions with optional rule_id, status, and limit filters
GET/workflows/{execution_id}Return raw execution data and pipeline_data_json
GET/workflows/{execution_id}/detailReturn the canonical execution inspector model
POST/workflows/{execution_id}/cancelCancel a running or waiting execution
POST/workflows/{execution_id}/rerunStart a new execution from the original trigger
GET/pipeline/runsList recent runs. status=active returns running and waiting runs
GET/pipeline/runs/{execution_id}Return one lightweight run envelope
GET/pipeline/ingest/activityReturn recent frame and rule-trigger activity
WS/ws/pipelineStream live execution events

Execution detail fields

FieldTypeDescription
idintegerWorkflow execution ID
rule_idintegerRule that ran
statusstringrunning, waiting, completed, failed, or cancelled
started_atdatetime or nullStart time
completed_atdatetime or nullCompletion time
rule_namestringRule display name
trigger_typestringTrigger type from the execution payload
trigger_summarystringServer-computed trigger summary
graphobject or nullImmutable graph snapshot captured at execution start
timelinelistStep timeline, including skipped graph nodes
cooloff_triggeredbooleanWhether the run consumed the rule cool-off window
errorstring or nullExecution error
can_cancelbooleanWhether cancel is available
can_rerunbooleanWhether rerun is available

Pipeline run fields

FieldTypeDescription
execution_idintegerWorkflow execution ID
rule_idintegerRule ID
rule_namestringRule display name
statusstringExecution status
started_atdatetimeStart time
completed_atdatetime or nullCompletion time
errorstring or nullError summary
nodeslistDAG nodes with id, label, step_type, and status
edgeslistDAG edges with source and target handles

Rules

MethodPathDescription
GET/rulesList rules with recent execution counts
POST/rulesCreate a rule
GET/rules/{rule_id}Get a rule with steps, contexts, dependencies, and cron triggers
PUT/rules/{rule_id}Update a rule
DELETE/rules/{rule_id}Delete a rule and related executions
POST/rules/{rule_id}/executeManually trigger a rule
GET/rules/{rule_id}/exportExport a portable rule bundle
POST/rules/import/previewValidate an import bundle
POST/rules/importImport a bundle

Rule fields

FieldTypeDescription
namestringRule name
descriptionstring or nullOptional description
enabledbooleanWhether the rule can run
trigger_typeslist[string]Trigger types: sensor_event, cron, manual, webhook, telegram, occupancy_duration, cts_window, dementia_signal
cron_trigger_idslist[integer]Shared cron schedules linked to the rule
primary_sensor_idstring or nullFallback sensor for context and manual media lookup
cool_off_minutesintegerMinimum time between completed cool-off-worthy runs
max_daily_triggersintegerDaily execution cap
max_concurrent_executionsintegerConcurrent execution cap
execution_timeout_minutesintegerExecution timeout
webhook_configobject or nullWebhook secret and settings
occupancy_configobject or nullOccupancy duration settings
telegram_trigger_configobject or nullTelegram command settings

Pipeline authoring

Pipelines are directed graphs. order is a deterministic tiebreaker, not the runtime sequence.

MethodPathDescription
GET/rules/{rule_id}/stepsList steps
POST/rules/{rule_id}/stepsAdd a step
PUT/rules/{rule_id}/steps/{step_id}Update a step
DELETE/rules/{rule_id}/steps/{step_id}Delete a step
PUT/rules/{rule_id}/steps/positionsBatch update canvas positions
GET/rules/{rule_id}/edgesList graph edges
PUT/rules/{rule_id}/edgesReplace all graph edges atomically
POST/rules/{rule_id}/validateValidate templates and graph structure

Pipeline step fields

FieldTypeDescription
idintegerStep ID
rule_idintegerParent rule ID
orderintegerStable ordering and graph tiebreaker
step_typestringRegistered step type
labelstring or nullSlug label used by template references
config_jsonobjectStep-specific configuration
enabledbooleanWhether the step can run
position_xnumberCanvas x-coordinate
position_ynumberCanvas y-coordinate

Pipeline edge fields

FieldTypeDescription
source_step_idintegerSource step
source_portstringSource output port. Defaults to main
target_step_idintegerTarget step
target_portstringTarget input port. Defaults to main

The validator rejects unknown step IDs, unknown ports, invalid graph structure, and duplicate outgoing edges for the same source port.

Pipeline metadata

MethodPathDescription
GET/pipeline/step-typesRegistered step types with schemas, UI hints, output schemas, tags, and output ports
GET/pipeline/channel-typesRegistered notification channel types
GET/pipeline/filter-typesRegistered context filter types
GET/pipeline/llm-modelsNamed LLM registry entries
GET/pipeline/data-keysTemplate autocomplete variables and step output schemas
POST/pipeline/cron/previewValidate a cron expression and preview next runs

Contexts, dependencies, and cron

MethodPathDescription
GET/rules/{rule_id}/contextsList context filters
POST/rules/{rule_id}/contextsAdd a context filter
DELETE/rules/{rule_id}/contexts/{context_id}Delete a context filter
GET/rules/{rule_id}/dependenciesList dependencies
POST/rules/{rule_id}/dependenciesAdd a dependency
DELETE/rules/{rule_id}/dependencies/{dependency_id}Delete a dependency
GET/cron-triggersList cron triggers
POST/cron-triggersCreate a cron trigger
PUT/cron-triggers/{trigger_id}Update a cron trigger
DELETE/cron-triggers/{trigger_id}Delete a cron trigger

Rooms and sensors

ResourceEndpoints
RoomsGET /rooms, POST /rooms, PUT /rooms/{id}, DELETE /rooms/{id}
SensorsGET /sensors, POST /sensors, PUT /sensors/{id}, DELETE /sensors/{id}
Home Assistant syncPOST /ha/sync/rooms, POST /ha/sync/sensors, GET /ha/entities, GET /ha/media-players

People and presence

MethodPathDescription
GET/personsList household members
POST/personsCreate a member
GET/persons/{person_id}Get member details
PATCH/persons/{person_id}Update a member
DELETE/persons/{person_id}Delete a member
POST/persons/{person_id}/enrollUpload face enrollment photos
GET/persons/{person_id}/enrollmentGet enrollment status
DELETE/persons/{person_id}/enrollmentDelete enrollment
GET/persons/locationsCurrent location envelopes for all tracked members
GET/persons/{person_id}/locationCurrent location envelope for one member
GET/persons/{person_id}/presence-historyPresence history
GET/rooms/{room_id}/occupantsCurrent room occupants
GET/persons/{person_id}/dwellDwell summary

Face detection fields

POST /identify and POST /identify-batch return face detection objects with these fields:

FieldTypeDescription
person_idstringEnrolled identity or "unknown"
namestringDisplay name
confidencefloatDeprecated raw similarity alias; do not use for authority decisions
similarityfloatRaw normalized-embedding cosine similarity
raw_similarityfloatSame value as similarity; the canonical field
calibrated_confidencefloat or nullCalibrated ArcFace probability in [0, 1]. Null when calibration is unavailable or the face is not recognized.
calibration_statusstringready, degraded_missing, degraded_incompatible, or degraded_invalid
calibration_artifact_versionstring or nullUUID of the active calibration artifact. Null when degraded.
arcface_model_versionstringActive ArcFace model version from the service config
model_profilestringActive model profile from the service config
preprocessing_versionstringActive preprocessing version from the service config
recognition_statestringrecognized, candidate, or unrecognized
best_candidate_idstring or nullNearest-centroid identity below threshold
bboxarrayBounding box [x1, y1, x2, y2] in pixels
yaw_degfloatHead yaw in degrees
pitch_degfloatHead pitch in degrees
roll_degfloatHead roll in degrees
det_scorefloatSCRFD detection confidence

calibrated_confidence is null whenever calibration_status is not ready, and is always null for candidate and unrecognized faces.

CTS endpoints

CTS routes cover camera admin, calibration, PH identity review, presence, signals, trajectories, live data, overlap groups, and CTS window triggers. They require CTS enablement and the appropriate API permissions.

Representative paths include:

PathPurpose
/cts/camerasCTS camera registration and health
/cts/calibration/*Homography, visibility, privacy zones, and adjacency
/cts/ph/*Person hypothesis lists, details, corrections, merges, splits, and deletes
/cts/identity/correction-targetsActive household members an operator may assign, with optional gallery decoration
/cts/identity/corrections/*Shared correction workflow: propose, apply, compensate, and job status
/cts/identity/reid-review/*Governed ReID gallery review queue: list, detail, approve, relabel, reject, batch reject, compensate, counts
/cts/keyframesGrouped physical-frame keyframe cards with effective identity per bbox
/cts/presence/*Presence configuration and snapshots
/cts/signals/*Dementia and routine-change signals
/cts/window-triggersCTS window trigger configuration
/cts/decisions/*Decision detail and explicit provenance retrieval
/cts/evidence/*Evidence history and diagnostics retrieval by PH, observation, or keyframe

Grouped keyframes

GET /api/v1/cts/keyframes returns one card per physical source frame, even when several Person Hypotheses triggered sampling of the same frame. Each card carries every visible bounding box with its server-computed effective identity, so a frame that shows two people returns two identities rather than only the identity of the PH that triggered the capture.

The orchestrator owns identity semantics. The card summary, Unknown count, and conflict count are derived once at the BFF from the per-bbox provenance; the browser computes none of them. Effective identity maps onto Cognitive Companion's internal person_id at the BFF boundary.

FieldTypeDescription
keyframesarrayPhysical-frame cards for the page
keyframes[].physical_frame_idstringDeterministic ID from (camera_id, minio_key, captured_at)
keyframes[].image_urlstring or nullPresigned URL for the raw frame, resolved per request
keyframes[].triggersarrayAudit trigger rows (keyframe_id, ph_id, tag_reason)
keyframes[].identity_summaryarrayEffective identities on the card with count and source_badges
keyframes[].unknown_countintegerBounding boxes with no effective identity
keyframes[].conflict_countintegerBounding boxes in identity conflict
keyframes[].pending_review_countintegerBounding boxes whose PH has a pending ReID candidate
keyframes[].bboxesarrayEvery deduplicated bbox with inferred_identity_id, effective_identity_id, person_id, authority, decision_source, calibrated_confidence, conflict, revision_id, and pending_review
countintegerCards on this page
totalintegerCards matching the filters before pagination
truncatedbooleanTrue when the upstream scan hit its window cap, so total counts only the most recent window

Server-side query parameters: person_id (effective household identity), camera_id, tag_reason, after, before, explicit_unknown, authority, decision_source, conflict_only, pending_review_only, limit, and offset. Filters apply before grouped-frame pagination; a matching frame still returns all of its bboxes for context. A malformed upstream envelope returns 502 with code keyframe.upstream_contract rather than an empty list. Requires cts.keyframes.view. The list_keyframe_frames MCP tool reads the same service function.

Identity correction workflow

A correction runs in two steps. The client first requests a segment proposal, then applies an explicit observation-bounded correction guarded by the proposal version token. The correction service writes the revision range, creates a projection job, and publishes one revision. A job completes only after every required projection acknowledges the same revision_id.

MethodPathDescription
POST/internal/corrections/proposeReturn an advisory segment proposal and its version token
POST/internal/corrections/applyApply a frame or observation-bounded correction, or an explicit Unknown
POST/internal/corrections/{correction_id}/compensateUndo a correction with a compensating revision
POST/internal/projection-acksAcknowledge a projection by revision_id

apply returns 409 when the version token is stale and 422 when a non-Unknown correction has no target identity. The whole-PH POST /internal/corrections endpoint is deprecated: it proposes the current segment and applies it, and is removed once the correction UI calls the explicit apply endpoint. The endpoint returns a Deprecation response header while it remains.

The Cognitive Companion BFF exposes the browser-facing side of this workflow. Both the Keyframes surface and the Person Hypothesis inspector call it through one service and one Vue component.

MethodPathDescription
POST/api/v1/cts/identity/corrections/proposeReturn a segment proposal with its version token
POST/api/v1/cts/identity/corrections/applyApply a frame or observation-bounded correction, or explicit Unknown
POST/api/v1/cts/identity/corrections/{correction_id}/compensateUndo a correction with a compensating revision
GET/api/v1/cts/identity/corrections/jobs/{revision_id}Projection-job status, polled until terminal

The BFF injects the audited actor from the authentication context; the apply request schema rejects a browser-supplied actor. It preserves the upstream 409 correction.stale_version and 422 statuses and maps an upstream 5xx to 502 correction.upstream. Proposing and reading job status require cts.identity.view; applying and compensating require cts.identity.correct. The job response includes status (pending, applying, completed, or failed), required_projections, row_counts, attempts, and last_error. The propose_identity_correction and get_identity_correction_job MCP tools read the same service functions.

ReID review queue

The review queue is the operator surface over the governed ReID gallery. It lists pending candidates, shows full crop and frame provenance with server-computed eligibility, and applies an approve, relabel, or reject decision. See ReID gallery governance for the lifecycle and trust rules.

MethodPathDescription
GET/api/v1/cts/identity/reid-review/candidatesPaginated candidates with state, identity, camera, model, and source filters
GET/api/v1/cts/identity/reid-review/candidates/{id}Candidate detail, review history, and eligibility
GET/api/v1/cts/identity/reid-review/candidates/{id}/eventsImmutable review history
GET/api/v1/cts/identity/reid-review/countsQueue counts by state for review indicators
POST/api/v1/cts/identity/reid-review/candidates/{id}/approveApprove one candidate (individual only)
POST/api/v1/cts/identity/reid-review/candidates/{id}/relabelRelabel one candidate to a household target, then verify
POST/api/v1/cts/identity/reid-review/candidates/{id}/rejectReject one candidate with a structured reason
POST/api/v1/cts/identity/reid-review/reject-batchReject several candidates, with per-item results
POST/api/v1/cts/identity/reid-review/candidates/{id}/compensateUn-verify an approved candidate

Every route requires the cts.identity.gallery_review permission. This is a strict token check: the broad GET /api/v1/* and POST /api/v1/cts/identity/* role patterns do not grant access on their own, so a caller holding only cts.identity.view or cts.identity.correct receives 403. The grant is held by the caregiver-admin and admin roles.

Approve and relabel re-check live eligibility and the optimistic audit_version server-side. A stale or now-ineligible candidate returns 409 with code reid_review.stale or reid_review.ineligible; a malformed upstream envelope returns 502 reid_review.upstream_contract. There is no bulk approve endpoint: batch selection exposes only rejection. The BFF injects the audited actor from the authentication context, presigns crop and frame media only for a live object (a rejected candidate's crop is deleted, so its URL is null), and maps the effective identity onto person_id.

This surface is operational biometric administration, not caregiver-facing domain data, so it is intentionally excluded from MCP parity. Exposing approve, relabel, or reject as an agent tool would let an unattended agent re-identify a household member without operator review. No MCP adapter duplicates the review service; the exemption is asserted in the router tests.

Knowledge and resident content

ResourceRepresentative endpoints
Knowledge documentsPOST /knowledge, GET /knowledge, GET /knowledge/{doc_id}, PATCH /knowledge/{doc_id}, approval, archive, restore, delete, re-embed
Knowledge imagesPOST /knowledge/{doc_id}/images, PATCH /knowledge/{doc_id}/images/{img_id}, DELETE /knowledge/{doc_id}/images/{img_id}
Info cardsCRUD, approve, archive, restore, suggest, and slot update endpoints under /info-cards
InteractionsGET /knowledge-interactions/queries, /quiz-sessions, and /info-card-deliveries

Webhooks

MethodPathDescription
POST/webhooks/{rule_id}Trigger a rule with the configured webhook secret
POST/webhooks/{rule_id}/generate-secretGenerate or rotate the rule webhook secret

Webhook requests use X-Webhook-Secret. The JSON body is available to the pipeline as trigger_input.

Errors

StatusMeaning
400Invalid operation for the resource state
401Missing or invalid authentication
403Authenticated key lacks permission
404Resource not found
409Conflict, such as a duplicate rule name or step label
422Validation error, including template or graph validation failures
503Required service unavailable

Released under the AGPL-3.0 License.