Event Store REST API

Endpoint reference for the on-device Event Store v2 API, including event schemas and administration routes.

The Event Store runs on a managed device and stores inference events produced by pipelines on that device. Base URL is http://<device-ip>:8001, and interactive Swagger documentation is served at /docs. See Services for the base URL, authentication, and error-shape rules shared by all on-device service APIs.

The v2 API accepts camelCase input (ex: base64Image, objectDetections) and returns snake_case responses.

This is not the cloud Vision Events API. The local contract uses event_schema, event_data, and inference_timestamp where the cloud uses eventType, useCaseId, and timestamp, and it takes image bytes directly rather than references to uploaded images. A cloud payload will not validate here.

If API_KEY is set on the service, every endpoint except /health requires an X-API-Key header. See Authentication.

curl -H "X-API-Key: $EVENT_STORE_API_KEY" \
  "http://<device-ip>:8001/v2/events/latest/query?limit=5"

Create an Event

Bounding box coordinates are center-based absolute pixels: x and y are the center of the box, width and height are the full dimensions. Confidence runs from 0.0 to 1.0.

Set draft: true to keep the event open so a video or local-only file can be attached after the fact, then finalize it. Omitting draft finalizes the event on creation, so existing producers are unaffected.

solution is optional in the schema but conditionally required at runtime. When cloud upload is enabled on the service and DEFAULT_SOLUTION_ID is not set, creating an event without solution returns 400. Either send it on every event or set the environment variable.

Create V2 Event

posthttp://device-ip:8001/v2/events
Authorizations
X-API-KeystringRequired
Bodyapplication/json
solutionstring · nullableOptional
workflow_idstring · nullableOptional
workflow_versionstring · nullableOptional
inference_timestampstringRequired
device_idstring · nullableOptional
stream_idstring · nullableOptional
image_idstring · nullableOptional
event_schemastringRequired
event_dataobjectRequired
custom_metadataobject · nullableOptional
imagesobject · V2ImageCreate[]Optional
Show properties
labelstring · nullableOptional
base64Imagestring · nullableOptional
inputBase64Imagestring · nullableOptional
objectDetectionsobject · V2ObjectDetection[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
classificationsobject · V2Classification[]Optional
Show properties
classstringRequired
confidencenumberRequired
instanceSegmentationsobject · V2InstanceSegmentation[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
pointsnumber[][]Required

Polygon points as [[x, y], ...] in absolute pixels

keypointsobject · V2Keypoint[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
keypointsobject · V2KeypointEntry[]Required
metadataobject · nullableOptional
displayImagePositioninteger · nullableOptional

Index into the images list indicating which image to display by default in a UI

draftbooleanOptional

True while the event is a draft: media may still be attached, and it is not yet uploaded. A draft is protected from cleanup only while cloud upload is enabled on the service. With cloud upload off, retention and capacity cleanup can delete an unfinished draft and its attachments.

Default: false
Responses
201Successful Responseapplication/json
idstringRequired
image_idsany[]Optional
created_atstringRequired
draftbooleanOptional

True while the event is a draft: media may still be attached, and it is not yet uploaded. A draft is protected from cleanup only while cloud upload is enabled on the service. With cloud upload off, retention and capacity cleanup can delete an unfinished draft and its attachments.

Default: false
messagestringOptional
Default: Event created successfully
400`event_data` does not conform to the named `event_schema`, an image whose `base64Image` or `inputBase64Image` failed to decode, or a missing `solution`: it is required when cloud upload is enabled unless DEFAULT_SOLUTION_ID is set on the service.application/json
detailstringRequired
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
413Record exceeds the maximum allowed sizeapplication/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to store the event.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
post/v2/events
POST /v2/events HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: application/json

{
  "solution": "text",
  "workflow_id": "text",
  "workflow_version": "text",
  "inference_timestamp": "text",
  "device_id": "text",
  "stream_id": "text",
  "image_id": "text",
  "event_schema": "text",
  "event_data": {},
  "custom_metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "images": [
    {
      "label": "text",
      "base64Image": "text",
      "inputBase64Image": "text",
      "objectDetections": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1
        }
      ],
      "classifications": [
        {
          "class": "text",
          "confidence": 1
        }
      ],
      "instanceSegmentations": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1,
          "points": [
            [
              1
            ]
          ]
        }
      ],
      "keypoints": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1,
          "keypoints": [
            {
              "id": 1,
              "x": 1,
              "y": 1,
              "occluded": true
            }
          ]
        }
      ],
      "metadata": {
        "ANY_ADDITIONAL_PROPERTY": "anything"
      }
    }
  ],
  "displayImagePosition": 1,
  "draft": false
}
Response
{
  "id": "text",
  "image_ids": [
    "anything"
  ],
  "created_at": "text",
  "draft": false,
  "message": "Event created successfully"
}

Query Events

GET /v2/events filters by time window, source, and custom metadata. metadata_filter takes key:value or key:op:value with the operators eq, ne, gt, lt, gte, and lte, and repeats with AND logic.

Per-image metadata is not queryable through metadata_filter. Only custom_metadata on the event is.

Get V2 Events

gethttp://device-ip:8001/v2/events

Get events with optional filtering. Returns every stored event, including any written by an earlier version of the service.

Authorizations
X-API-KeystringRequired
Query parameters
start_timestringOptional

ISO8601 timestamp to start from (filters by created_at)

limitintegerOptional

Maximum number of events to return

Default: 100
end_timestringOptional

ISO8601 timestamp to end at (filters by created_at)

device_idstringOptional

Filter by device_id (exact match)

event_schemastringOptional

Filter by event_schema (exact match)

workflow_idstringOptional

Filter by workflow_id (exact match)

external_idstringOptional

Filter by external_id (exact match)

related_event_idstringOptional

Filter by related_event_id (for feedback events)

sort_directionstringOptional

Sort direction: 'asc' or 'desc'

Default: desc
device_id__instringOptional

Filter by multiple device_ids (comma-separated)

event_schema__instringOptional

Filter by multiple event_schemas (comma-separated)

workflow_id__instringOptional

Filter by multiple workflow_ids (comma-separated)

external_id__instringOptional

Filter by multiple external_ids (comma-separated)

metadata_filterstring[]Optional

Filter by custom_metadata. Format: 'key:value' or 'key:op:value'. Operators: eq, ne, gt, lt, gte, lte.

Default: []
include_draftsbooleanOptional

Include draft (not yet finalized) events. Set false to see only finalized events.

Default: true
Responses
200Successful Responseapplication/json
eventsobject · V2Event[]Required
Show properties
idstringRequired
solutionstring · nullableOptional
workflow_idstring · nullableOptional
workflow_versionstring · nullableOptional
inference_timestampstringRequired
device_idstring · nullableOptional
stream_idstring · nullableOptional
imagesobject · V2ImageResponse[]Optional
Show properties
file_idstring · nullableOptional
input_file_idstring · nullableOptional
labelstring · nullableOptional
object_detectionsobject · V2ObjectDetection[]Optional
classificationsobject · V2Classification[]Optional
instance_segmentationsobject · V2InstanceSegmentation[]Optional
keypointsobject · V2Keypoint[]Optional
metadataobject · nullableOptional
videosobject · V2VideoResponse[]Optional
Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
local_only_filesobject · V2LocalOnlyFileResponse[]Optional

Files attached to this event that are stored on-device only and never uploaded to the cloud (e.g. inspection blobs, thumbnails, arbitrary JSON). Served via GET /local-only-files/{file_id}.

Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
display_image_positioninteger · nullableOptional
event_schemastringRequired
event_dataobjectRequired
custom_metadataobject · nullableOptional
created_atstringRequired
api_versionstringOptional
Default: v2
original_file_countintegerOptional
Default: 0
current_file_countintegerOptional
Default: 0
draftbooleanOptional

True while the event is a draft: media may still be attached, and it is not yet uploaded. A draft is protected from cleanup only while cloud upload is enabled on the service. With cloud upload off, retention and capacity cleanup can delete an unfinished draft and its attachments.

Default: false
finalized_atstring · nullableOptional

When the event was finalized (null while draft)

auto_finalized_atstring · nullableOptional

Set when the event was force-finalized by the DRAFT_AUTO_FINALIZE_SECONDS sweep

countintegerRequired
next_timestampstring · nullableOptional
400Invalid filter: a malformed timestamp, a `sort_direction` other than `asc` or `desc`, or an unparseable metadata_filter. An out-of-range `limit` is caught by request validation instead and returns 422.application/json
detailstringRequired
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to retrieve events.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/v2/events
GET /v2/events HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "events": [
    {
      "id": "text",
      "solution": "text",
      "workflow_id": "text",
      "workflow_version": "text",
      "inference_timestamp": "text",
      "device_id": "text",
      "stream_id": "text",
      "images": [
        {
          "file_id": "text",
          "input_file_id": "text",
          "label": "text",
          "object_detections": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1
            }
          ],
          "classifications": [
            {
              "class": "text",
              "confidence": 1
            }
          ],
          "instance_segmentations": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1,
              "points": [
                [
                  1
                ]
              ]
            }
          ],
          "keypoints": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1,
              "keypoints": [
                {
                  "id": 1,
                  "x": 1,
                  "y": 1,
                  "occluded": true
                }
              ]
            }
          ],
          "metadata": {}
        }
      ],
      "videos": [
        {
          "file_id": "text",
          "label": "text",
          "content_type": "text",
          "size_bytes": 1
        }
      ],
      "local_only_files": [
        {
          "file_id": "text",
          "label": "text",
          "content_type": "text",
          "size_bytes": 1
        }
      ],
      "display_image_position": 1,
      "event_schema": "text",
      "event_data": {},
      "custom_metadata": {},
      "created_at": "text",
      "api_version": "v2",
      "original_file_count": 0,
      "current_file_count": 0,
      "draft": false,
      "finalized_at": "text",
      "auto_finalized_at": "text"
    }
  ],
  "count": 1,
  "next_timestamp": "text"
}

Get V2 Event By Id

gethttp://device-ip:8001/v2/events/{event_id}

Get a specific event by ID. Returns every stored event, including any written by an earlier version of the service.

Authorizations
X-API-KeystringRequired
Path parameters
event_idstringRequired
Responses
200Successful Responseapplication/json
idstringRequired
solutionstring · nullableOptional
workflow_idstring · nullableOptional
workflow_versionstring · nullableOptional
inference_timestampstringRequired
device_idstring · nullableOptional
stream_idstring · nullableOptional
imagesobject · V2ImageResponse[]Optional
Show properties
file_idstring · nullableOptional
input_file_idstring · nullableOptional
labelstring · nullableOptional
object_detectionsobject · V2ObjectDetection[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
classificationsobject · V2Classification[]Optional
Show properties
classstringRequired
confidencenumberRequired
instance_segmentationsobject · V2InstanceSegmentation[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
pointsnumber[][]Required

Polygon points as [[x, y], ...] in absolute pixels

keypointsobject · V2Keypoint[]Optional
Show properties
classstringRequired
xnumberRequired

Center X of bounding box in absolute pixels

ynumberRequired

Center Y of bounding box in absolute pixels

widthnumberRequired

Full width of bounding box in pixels

heightnumberRequired

Full height of bounding box in pixels

confidencenumberRequired
keypointsobject · V2KeypointEntry[]Required
metadataobject · nullableOptional
videosobject · V2VideoResponse[]Optional
Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
local_only_filesobject · V2LocalOnlyFileResponse[]Optional

Files attached to this event that are stored on-device only and never uploaded to the cloud (e.g. inspection blobs, thumbnails, arbitrary JSON). Served via GET /local-only-files/{file_id}.

Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
display_image_positioninteger · nullableOptional
event_schemastringRequired
event_dataobjectRequired
custom_metadataobject · nullableOptional
created_atstringRequired
api_versionstringOptional
Default: v2
original_file_countintegerOptional
Default: 0
current_file_countintegerOptional
Default: 0
draftbooleanOptional

True while the event is a draft: media may still be attached, and it is not yet uploaded. A draft is protected from cleanup only while cloud upload is enabled on the service. With cloud upload off, retention and capacity cleanup can delete an unfinished draft and its attachments.

Default: false
finalized_atstring · nullableOptional

When the event was finalized (null while draft)

auto_finalized_atstring · nullableOptional

Set when the event was force-finalized by the DRAFT_AUTO_FINALIZE_SECONDS sweep

401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Event not found.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to retrieve the event.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/v2/events/{event_id}
GET /v2/events/{event_id} HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "id": "text",
  "solution": "text",
  "workflow_id": "text",
  "workflow_version": "text",
  "inference_timestamp": "text",
  "device_id": "text",
  "stream_id": "text",
  "images": [
    {
      "file_id": "text",
      "input_file_id": "text",
      "label": "text",
      "object_detections": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1
        }
      ],
      "classifications": [
        {
          "class": "text",
          "confidence": 1
        }
      ],
      "instance_segmentations": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1,
          "points": [
            [
              1
            ]
          ]
        }
      ],
      "keypoints": [
        {
          "class": "text",
          "x": 1,
          "y": 1,
          "width": 1,
          "height": 1,
          "confidence": 1,
          "keypoints": [
            {
              "id": 1,
              "x": 1,
              "y": 1,
              "occluded": true
            }
          ]
        }
      ],
      "metadata": {}
    }
  ],
  "videos": [
    {
      "file_id": "text",
      "label": "text",
      "content_type": "text",
      "size_bytes": 1
    }
  ],
  "local_only_files": [
    {
      "file_id": "text",
      "label": "text",
      "content_type": "text",
      "size_bytes": 1
    }
  ],
  "display_image_position": 1,
  "event_schema": "text",
  "event_data": {},
  "custom_metadata": {},
  "created_at": "text",
  "api_version": "v2",
  "original_file_count": 0,
  "current_file_count": 0,
  "draft": false,
  "finalized_at": "text",
  "auto_finalized_at": "text"
}

Get Latest V2 Events

gethttp://device-ip:8001/v2/events/latest/query

Get the most recent events, no timestamp required. Returns every stored event, including any written by an earlier version of the service.

Authorizations
X-API-KeystringRequired
Query parameters
limitintegerOptional

Maximum number of events to return

Default: 100
include_draftsbooleanOptional

Include draft (not yet finalized) events. Set false to see only finalized events.

Default: true
Responses
200Successful Responseapplication/json
eventsobject · V2Event[]Required
Show properties
idstringRequired
solutionstring · nullableOptional
workflow_idstring · nullableOptional
workflow_versionstring · nullableOptional
inference_timestampstringRequired
device_idstring · nullableOptional
stream_idstring · nullableOptional
imagesobject · V2ImageResponse[]Optional
Show properties
file_idstring · nullableOptional
input_file_idstring · nullableOptional
labelstring · nullableOptional
object_detectionsobject · V2ObjectDetection[]Optional
classificationsobject · V2Classification[]Optional
instance_segmentationsobject · V2InstanceSegmentation[]Optional
keypointsobject · V2Keypoint[]Optional
metadataobject · nullableOptional
videosobject · V2VideoResponse[]Optional
Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
local_only_filesobject · V2LocalOnlyFileResponse[]Optional

Files attached to this event that are stored on-device only and never uploaded to the cloud (e.g. inspection blobs, thumbnails, arbitrary JSON). Served via GET /local-only-files/{file_id}.

Show properties
file_idstringRequired
labelstring · nullableOptional
content_typestring · nullableOptional
size_bytesinteger · nullableOptional
display_image_positioninteger · nullableOptional
event_schemastringRequired
event_dataobjectRequired
custom_metadataobject · nullableOptional
created_atstringRequired
api_versionstringOptional
Default: v2
original_file_countintegerOptional
Default: 0
current_file_countintegerOptional
Default: 0
draftbooleanOptional

True while the event is a draft: media may still be attached, and it is not yet uploaded. A draft is protected from cleanup only while cloud upload is enabled on the service. With cloud upload off, retention and capacity cleanup can delete an unfinished draft and its attachments.

Default: false
finalized_atstring · nullableOptional

When the event was finalized (null while draft)

auto_finalized_atstring · nullableOptional

Set when the event was force-finalized by the DRAFT_AUTO_FINALIZE_SECONDS sweep

countintegerRequired
next_timestampstring · nullableOptional
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to retrieve events.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/v2/events/latest/query
GET /v2/events/latest/query HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "events": [
    {
      "id": "text",
      "solution": "text",
      "workflow_id": "text",
      "workflow_version": "text",
      "inference_timestamp": "text",
      "device_id": "text",
      "stream_id": "text",
      "images": [
        {
          "file_id": "text",
          "input_file_id": "text",
          "label": "text",
          "object_detections": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1
            }
          ],
          "classifications": [
            {
              "class": "text",
              "confidence": 1
            }
          ],
          "instance_segmentations": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1,
              "points": [
                [
                  1
                ]
              ]
            }
          ],
          "keypoints": [
            {
              "class": "text",
              "x": 1,
              "y": 1,
              "width": 1,
              "height": 1,
              "confidence": 1,
              "keypoints": [
                {
                  "id": 1,
                  "x": 1,
                  "y": 1,
                  "occluded": true
                }
              ]
            }
          ],
          "metadata": {}
        }
      ],
      "videos": [
        {
          "file_id": "text",
          "label": "text",
          "content_type": "text",
          "size_bytes": 1
        }
      ],
      "local_only_files": [
        {
          "file_id": "text",
          "label": "text",
          "content_type": "text",
          "size_bytes": 1
        }
      ],
      "display_image_position": 1,
      "event_schema": "text",
      "event_data": {},
      "custom_metadata": {},
      "created_at": "text",
      "api_version": "v2",
      "original_file_count": 0,
      "current_file_count": 0,
      "draft": false,
      "finalized_at": "text",
      "auto_finalized_at": "text"
    }
  ],
  "count": 1,
  "next_timestamp": "text"
}

Get Event Count

gethttp://device-ip:8001/events/count/stats

Get event count and statistics

Authorizations
X-API-KeystringRequired
Query parameters
device_idstringOptional

Filter by device_id

event_schemastringOptional

Filter by event_schema

workflow_idstringOptional

Filter by workflow_id

Responses
200Successful Responseapplication/json
total_countintegerRequired

Total number of events

filtered_countintegerRequired

Number of events matching filters

oldest_timestampstring · nullableOptional

Timestamp of oldest event (ISO8601)

newest_timestampstring · nullableOptional

Timestamp of newest event (ISO8601)

401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to get the event count.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/events/count/stats
GET /events/count/stats HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "total_count": 1,
  "filtered_count": 1,
  "oldest_timestamp": "text",
  "newest_timestamp": "text"
}

Draft Lifecycle

A producer that needs to attach a video encoded after the pass/fail decision creates the event as a draft, uploads the file when it is ready, then finalizes:

EVENT_ID=$(curl -s -X POST http://<device-ip>:8001/v2/events \
  -H "Content-Type: application/json" \
  -d '{"inference_timestamp":"2025-01-30T14:30:00Z","event_schema":"quality_check","event_data":{"result":"pass"},"solution":"a1b2c3d4e5f67890","draft":true}' \
  | jq -r '.id')

curl -X POST "http://<device-ip>:8001/v2/events/$EVENT_ID/videos" -F "file=@clip.mp4"
curl -X POST "http://<device-ip>:8001/v2/events/$EVENT_ID/finalize"

Until an event is finalized it is skipped by cloud upload. It is also protected from cleanup, but only while cloud upload is enabled on the service. With cloud upload off, a draft is as deletable as any other record, so retention and capacity cleanup can remove one that is still being assembled.

A draft whose producer never calls finalize is force-closed after DRAFT_AUTO_FINALIZE_SECONDS. Both finalized_at and auto_finalized_at are set in that case, so read auto_finalized_at to tell a force-closed event from one the producer finalized itself.

Attachment routes add bytes, so unlike finalize they are subject to capacity backpressure: when the store is over its limits they return 529 and the upload is not accepted.

Upload Video To Event

posthttp://device-ip:8001/v2/events/{event_id}/videos

Attach a video to a draft event.

The event must have been created with draft=true and not yet finalized - finalized events may already be in the cloud upload queue, so a late-attached video would silently never be backed up (409). The upload is multipart/form-data (no base64 overhead), parsed as a stream: the body is written straight to a staging file with MAX_VIDEO_UPLOAD_BYTES enforced per chunk, so an oversized (or misdirected) upload is rejected without ever spooling the full body to disk or memory, and the draft check runs before the body is consumed at all. The file must be a recognized video format (detected from content, not the declared content type).

Attached videos are served locally via GET /videos/{file_id} and appear in the event's videos array on the v2 GET endpoints.

Authorizations
X-API-KeystringRequired
Path parameters
event_idstringRequired
Bodymultipart/form-data
filestringRequired

Video file

labelstringOptional

Label for the video (e.g. 'camera_1_video')

Default: video
Responses
201Successful Responseapplication/json
file_idstringRequired
event_idstringRequired
labelstring · nullableOptional
content_typestringRequired
size_bytesintegerRequired
messagestringOptional
Default: Video attached successfully
400Malformed multipart body, or a missing, empty, or duplicate `file` part.application/json
detailstringRequired
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Event not found.application/json
detailstringRequired
409Event is already finalized. Videos attach only to drafts.application/json
detailstringRequired
413Video exceeds MAX_VIDEO_UPLOAD_BYTES.application/json
detailstringRequired
415Content is not a supported video format. The format is detected from the bytes, not the declared type.application/json
detailstringRequired
422Validation Errorapplication/json
one ofOptional
Show properties
object · ErrorResponseOptional

Error raised by the service. detail is a string here, unlike HTTPValidationError where it is an array.

Show properties
detailstringRequired
object · HTTPValidationErrorOptional
Show properties
detailobject · ValidationError[]Optional
500Failed to store the video.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
post/v2/events/{event_id}/videos
POST /v2/events/{event_id}/videos HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Content-Type: multipart/form-data
Accept: application/json

{
  "file": "binary",
  "label": "video"
}
Response
{
  "file_id": "text",
  "event_id": "text",
  "label": "text",
  "content_type": "text",
  "size_bytes": 1,
  "message": "Video attached successfully"
}

Upload Local Only File To Event

posthttp://device-ip:8001/v2/events/{event_id}/local-only-files

Attach a local-only file to a draft event.

Local-only files are stored on-device and are never uploaded to the cloud - regardless of content type (they may be inspection blobs, JSON, or thumbnails). This is the explicit, first-class alternative to smuggling large non-queryable payloads through queryable metadata fields.

Like video attach, the event must have been created with draft=true and not yet finalized (409 otherwise), and the body is streamed to a staging file with max_local_only_file_upload_bytes enforced per chunk so an oversized upload is rejected without ever spooling the full body to memory or disk. Unlike video attach, no content type is enforced; the client may declare a content_type or let it be sniffed from the bytes.

Attached files are served locally via GET /local-only-files/{file_id} and appear in the event's local_only_files array on the v2 GET endpoints.

Authorizations
X-API-KeystringRequired
Path parameters
event_idstringRequired
Bodymultipart/form-data
filestringRequired

Arbitrary file to store on-device only (never backed up)

labelstringOptional

Label for the file (e.g. 'inspection_blob')

Default: file
content_typestringOptional

Optional MIME type to store and serve the file with (e.g. 'application/json'). If omitted, the type is sniffed from the file content.

Responses
201Successful Responseapplication/json
file_idstringRequired
event_idstringRequired
labelstring · nullableOptional
content_typestringRequired
size_bytesintegerRequired
messagestringOptional
Default: Local-only file attached successfully
400Malformed or incomplete multipart body, missing/empty/duplicate 'file' partapplication/json
detailstringRequired
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Event not foundapplication/json
detailstringRequired
409Event is already finalized (local-only files attach to drafts only)application/json
detailstringRequired
413File exceeds the maximum upload sizeapplication/json
detailstringRequired
422Invalid label or content_typeapplication/json
one ofOptional
Show properties
object · ErrorResponseOptional

Error raised by the service. detail is a string here, unlike HTTPValidationError where it is an array.

Show properties
detailstringRequired
object · HTTPValidationErrorOptional
Show properties
detailobject · ValidationError[]Optional
500Failed to store the file.application/json
detailstringRequired
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
post/v2/events/{event_id}/local-only-files
POST /v2/events/{event_id}/local-only-files HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Content-Type: multipart/form-data
Accept: application/json

{
  "file": "binary",
  "label": "file",
  "content_type": "text"
}
Response
{
  "file_id": "text",
  "event_id": "text",
  "label": "text",
  "content_type": "text",
  "size_bytes": 1,
  "message": "Local-only file attached successfully"
}

Finalize V2 Event

posthttp://device-ip:8001/v2/events/{event_id}/finalize

Finalize a draft event so it enters the upload/cleanup lifecycle.

Idempotent: finalizing an already-finalized event is a no-op that returns the existing state (already_finalized=true). If the event was already force-closed by the DRAFT_AUTO_FINALIZE_SECONDS sweep, auto_finalized_at is set in the response.

This endpoint stays available while the device is capacity-blocked (529) because finalizing drafts is how a draft-saturated store starts draining.

Authorizations
X-API-KeystringRequired
Path parameters
event_idstringRequired
Responses
200Successful Responseapplication/json
idstringRequired
finalized_atstringRequired
already_finalizedbooleanRequired

True when the event was already finalized before this call (no-op)

auto_finalized_atstring · nullableOptional

Set when the event had already been force-finalized by the auto-finalize sweep

messagestringOptional
Default: Event finalized
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Event not found.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Failed to finalize the event.application/json
detailstringRequired
post/v2/events/{event_id}/finalize
POST /v2/events/{event_id}/finalize HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "id": "text",
  "finalized_at": "text",
  "already_finalized": true,
  "auto_finalized_at": "text",
  "message": "Event finalized"
}

Event Schemas

event_schema selects the structure of event_data. Each schema forbids fields it does not define, and every field accepts both its camelCase and snake_case spelling.

The two fields fail differently. A bad event_schema returns 422. An event_data payload that does not conform to the named schema returns 400, with a string detail naming the schema.

FieldTypeRequiredConstraint
result"pass" or "fail"Yes
externalIdstringNoUp to 1000 characters
{ "result": "pass", "externalId": "SKU-12345" }

Download Files

Image IDs are ephemeral. Cleanup can remove a file at any time, so handle 404 and do not cache IDs beyond a single session. Compare current_file_count against original_file_count on an event to tell whether its files were cleaned up.

Get Image

gethttp://device-ip:8001/images/{image_id}

Get an image or video by ID. Supports HTTP Range requests for efficient video streaming.

Authorizations
X-API-KeystringRequired
Path parameters
image_idstringRequired
Header parameters
rangestring · nullableOptional

Byte range to request. Supports formats: bytes=start-end, bytes=start-, bytes=-suffix

Responses
200Full content returnedapplication/json
anyOptional
206Partial content returned (response to Range request)image/*
stringOptional
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404File not foundapplication/json
detailstringRequired
416Range not satisfiableapplication/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/images/{image_id}
GET /images/{image_id} HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
"anything"

Get Video

gethttp://device-ip:8001/videos/{video_id}

Get a video by ID. Supports HTTP Range requests for efficient streaming.

Returns 404 if the file exists but is not a video.

Authorizations
X-API-KeystringRequired
Path parameters
video_idstringRequired
Header parameters
rangestring · nullableOptional

Byte range to request. Supports formats: bytes=start-end, bytes=start-, bytes=-suffix

Responses
200Full content returnedapplication/json
anyOptional
206Partial content returned (response to Range request)video/*
stringOptional
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Video not foundapplication/json
detailstringRequired
416Range not satisfiableapplication/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/videos/{video_id}
GET /videos/{video_id} HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
"anything"

Get Local Only File

gethttp://device-ip:8001/local-only-files/{file_id}

Get a local-only file by ID. Supports HTTP Range requests.

Local-only files are attached to a draft event via POST /v2/events/{event_id}/local-only-files and are stored on-device only - they are never uploaded to the cloud. Returns 404 if the file exists but is not a local-only file, so this route cannot be used to fetch ordinary images or videos.

Authorizations
X-API-KeystringRequired
Path parameters
file_idstringRequired
Header parameters
rangestring · nullableOptional

Byte range to request. Supports formats: bytes=start-end, bytes=start-, bytes=-suffix

Responses
200Full content returnedapplication/json
anyOptional
206Partial content returned (response to Range request)application/octet-stream
stringOptional
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
404Local-only file not foundapplication/json
detailstringRequired
416Range not satisfiableapplication/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
529Store is over its capacity limits and is waiting for uploads to drain (`capacity_blocked`). The request is rejected before any data is written.application/json
detailstringRequired
errorstring · enumRequired
Possible values:capacity_blocked
get/local-only-files/{file_id}
GET /local-only-files/{file_id} HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
"anything"

Statistics and Health

/stats reports current usage, the active configuration, capacity against each limit, and what the next cleanup pass will delete. Alert on capacity.storage.percent_used and capacity.records.percent_used above 80%.

Get Stats

gethttp://device-ip:8001/stats

Get comprehensive statistics about events and images including capacity and cleanup predictions

Authorizations
X-API-KeystringRequired
Responses
200Successful Responseapplication/json
currentobject · StatsCurrentSectionRequired

Current state of the system

Show properties
total_eventsintegerRequired

Number of events stored

total_imagesintegerRequired

Number of image files stored

total_storage_bytesintegerRequired

Total bytes used by images

total_storage_formattedstringRequired

Total storage in human-readable format (binary units)

oldest_event_timestampstring · nullableOptional

Timestamp of oldest event (ISO8601)

newest_event_timestampstring · nullableOptional

Timestamp of newest event (ISO8601)

days_of_data_storednumber · nullableOptional

Time range of stored data in days

time_until_oldest_data_deletedstring · nullableOptional

Human-readable time until oldest data is deleted

draft_eventsintegerOptional

Number of draft events awaiting finalization

Default: 0
oldest_draft_age_secondsinteger · nullableOptional

Age of the oldest draft event in seconds (None when no drafts)

configurationobject · StatsConfigurationSectionRequired

Current ENV configuration values

Show properties
data_dirstringRequired

Data directory path

retention_daysnumberRequired

Number of days to retain data before deletion

max_recordsintegerRequired

Maximum number of event records allowed

max_record_size_bytesintegerRequired

Maximum size for a single event record

max_record_size_formattedstringRequired

Maximum record size in human-readable format

max_storage_bytesintegerRequired

Maximum total storage for image files

max_storage_formattedstringRequired

Maximum storage in human-readable format

cleanup_interval_secondsintegerRequired

How often cleanup runs (in seconds)

capacityobject · StatsCapacitySectionRequired

Utilization metrics

Show properties
recordsobject · StatsCapacityRecordsRequired

Record count capacity metrics

Show properties
usedintegerRequired

Number of records currently stored

limitintegerRequired

Maximum number of records allowed

percent_usednumberRequired

Percentage of record capacity used

storageobject · StatsCapacityStorageRequired

Storage capacity metrics

Show properties
bytes_usedintegerRequired

Total bytes currently used

bytes_used_formattedstringRequired

Bytes used in human-readable format

bytes_limitintegerRequired

Maximum bytes allowed

bytes_limit_formattedstringRequired

Bytes limit in human-readable format

percent_usednumberRequired

Percentage of storage capacity used

averagesobject · StatsCapacityAveragesRequired

Average metrics

Show properties
record_size_bytesintegerRequired

Average size of a record in bytes

record_size_formattedstringRequired

Average record size in human-readable format

images_per_eventnumberRequired

Average number of images per event

next_cleanup_will_deleteobject · StatsNextCleanupSectionRequired

Predictions for next cleanup run

Show properties
retention_cutoff_timestampstringRequired

Data older than this will be deleted (ISO8601)

records_past_retentionintegerRequired

Number of records past retention period that cleanup can delete (excludes drafts while cloud upload is enabled)

files_past_retentionintegerRequired

Number of files past retention period

bytes_past_retentionintegerRequired

Bytes that will be freed from old files

bytes_past_retention_formattedstringRequired

Bytes to be freed in human-readable format

excess_records_over_limitintegerRequired

Records over the max_records limit

excess_bytes_over_limitintegerRequired

Bytes over the max_storage_bytes limit

excess_bytes_formattedstringRequired

Excess bytes in human-readable format

401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
500Failed to get stats.application/json
detailstringRequired
get/stats
GET /stats HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "current": {
    "total_events": 1,
    "total_images": 1,
    "total_storage_bytes": 1,
    "total_storage_formatted": "text",
    "oldest_event_timestamp": "text",
    "newest_event_timestamp": "text",
    "days_of_data_stored": 1,
    "time_until_oldest_data_deleted": "text",
    "draft_events": 0,
    "oldest_draft_age_seconds": 1
  },
  "configuration": {
    "data_dir": "text",
    "retention_days": 1,
    "max_records": 1,
    "max_record_size_bytes": 1,
    "max_record_size_formatted": "text",
    "max_storage_bytes": 1,
    "max_storage_formatted": "text",
    "cleanup_interval_seconds": 1
  },
  "capacity": {
    "records": {
      "used": 1,
      "limit": 1,
      "percent_used": 1
    },
    "storage": {
      "bytes_used": 1,
      "bytes_used_formatted": "text",
      "bytes_limit": 1,
      "bytes_limit_formatted": "text",
      "percent_used": 1
    },
    "averages": {
      "record_size_bytes": 1,
      "record_size_formatted": "text",
      "images_per_event": 1
    }
  },
  "next_cleanup_will_delete": {
    "retention_cutoff_timestamp": "text",
    "records_past_retention": 1,
    "files_past_retention": 1,
    "bytes_past_retention": 1,
    "bytes_past_retention_formatted": "text",
    "excess_records_over_limit": 1,
    "excess_bytes_over_limit": 1,
    "excess_bytes_formatted": "text"
  }
}

Health Check

gethttp://device-ip:8001/health
Responses
200Successful Responseapplication/json
statusstringRequired

Overall health status

datastorestringRequired

Datastore health status

errorstring · nullableOptional

Error message if unhealthy

get/health
GET /health HTTP/1.1
Host: device-ip:8001
Accept: application/json
Response
{
  "status": "text",
  "datastore": "text",
  "error": "text"
}

Administration

Manual Cleanup

posthttp://device-ip:8001/admin/cleanup

Manually trigger cleanup process (bypasses normal schedule)

This endpoint allows operators to manually trigger data cleanup based on retention policies and storage limits. Useful for: - Freeing storage space immediately instead of waiting for scheduled cleanup - Testing cleanup behavior - Emergency capacity management

The cleanup process will: 1. Delete records older than retention_days 2. Delete oldest records if total exceeds max_records 3. Delete oldest files if total storage exceeds max_storage_bytes

Returns detailed metrics about what was deleted and current storage state.

Authorizations
X-API-KeystringRequired
Responses
200Successful Responseapplication/json
triggerstringRequired

How cleanup was triggered (MANUAL or AUTOMATIC)

duration_secondsnumberRequired

How long cleanup took to run

records_deletedobject · CleanupDeletedCountsRequired

Counts of deleted items

Show properties
totalintegerRequired

Total items deleted

retentionintegerRequired

Items deleted due to retention policy

overlimitintegerRequired

Items deleted due to being over limit

storageinteger · nullableOptional

Files deleted due to storage limits (files_deleted only)

files_deletedobject · CleanupDeletedCountsRequired

Counts of deleted items

Show properties
totalintegerRequired

Total items deleted

retentionintegerRequired

Items deleted due to retention policy

overlimitintegerRequired

Items deleted due to being over limit

storageinteger · nullableOptional

Files deleted due to storage limits (files_deleted only)

bytes_freedintegerRequired

Total bytes freed by cleanup

beforeobject · CleanupStateCountsRequired

State counts before or after cleanup

Show properties
recordsintegerRequired

Number of records

filesintegerRequired

Number of files

bytesintegerRequired

Total bytes used

afterobject · CleanupStateCountsRequired

State counts before or after cleanup

Show properties
recordsintegerRequired

Number of records

filesintegerRequired

Number of files

bytesintegerRequired

Total bytes used

consistencyobject · CleanupConsistencyInfoRequired

Consistency check results

Show properties
ranbooleanRequired

Whether consistency check ran this cleanup

dangling_db_records_removedintegerRequired

DB records removed because file was missing from disk

orphaned_disk_files_removedintegerRequired

Disk files removed because not in DB

messagestringRequired

Human-readable summary message

401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
500Cleanup failed.application/json
detailstringRequired
post/admin/cleanup
POST /admin/cleanup HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "trigger": "text",
  "duration_seconds": 1,
  "records_deleted": {
    "total": 1,
    "retention": 1,
    "overlimit": 1,
    "storage": 1
  },
  "files_deleted": {
    "total": 1,
    "retention": 1,
    "overlimit": 1,
    "storage": 1
  },
  "bytes_freed": 1,
  "before": {
    "records": 1,
    "files": 1,
    "bytes": 1
  },
  "after": {
    "records": 1,
    "files": 1,
    "bytes": 1
  },
  "consistency": {
    "ran": true,
    "dangling_db_records_removed": 1,
    "orphaned_disk_files_removed": 1
  },
  "message": "text"
}

Resetting takes two calls so it cannot happen by accident. /reset/request returns a single-use token valid for 60 seconds, and /reset/confirm performs the deletion.

A confirmed reset permanently deletes every event and file in the store. It cannot be undone.

Reset Request

posthttp://device-ip:8001/reset/request

Request a reset token (step 1 of 2)

Authorizations
X-API-KeystringRequired
Responses
200Successful Responseapplication/json
reset_tokenstringRequired

Token to use for reset confirmation

expires_in_secondsintegerRequired

Number of seconds until token expires

messagestringRequired

Instructions for using the token

401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
post/reset/request
POST /reset/request HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Accept: application/json
Response
{
  "reset_token": "text",
  "expires_in_seconds": 1,
  "message": "text"
}

Reset Confirm

posthttp://device-ip:8001/reset/confirm

Confirm reset and delete all data (step 2 of 2)

Authorizations
X-API-KeystringRequired
Bodyapplication/json
reset_tokenstringRequired
Responses
200Successful Responseapplication/json
statusstringRequired

Status of the reset operation

messagestringRequired

Confirmation message

400Missing, invalid, or expired reset token.application/json
detailstringRequired
401Missing or invalid `X-API-Key`. Only returned when API_KEY is set on the service; authentication is disabled by default.application/json
detailstringRequired
422Validation Errorapplication/json
detailobject · ValidationError[]Optional
Show properties
locany[]Required
msgstringRequired
typestringRequired
inputanyOptional
ctxobjectOptional
500Reset failed.application/json
detailstringRequired
post/reset/confirm
POST /reset/confirm HTTP/1.1
Host: device-ip:8001
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: application/json

{
  "reset_token": "text"
}
Response
{
  "status": "text",
  "message": "text"
}