Milestone XProtect WebSockets Messaging API (1.0.0)

Events and State WebSocket API

Introduction

Use the Events and State WebSocket API to subscribe to events in the VMS. Events will be pushed to the recipient through the established WebSocket connection. The API uses a filter mechanism to control the events of interest, this can be modified during the lifetime of the connection.

Requirements

  • A system running XProtect 2023 R3 or later. You are recommended to set up a small separate system for development. If you don't have one, install XProtect following the Get started guide.
  • A Basic user or Windows user with access to some devices. If you don't have one, go to Create basic users.

NOTE:
User credentials, bearer tokens, and other sensitive data are transmitted in cleartext. It is highly recommended to set up the VMS to be secured (using HTTPS / WSS).

WebSocket connection

Connect to the Events & State service to set up a session to start receiving events. To connect, start a secure WebSockets connection at:

wss://{api-gateway}/api/ws/events/v1

or if the VMS is unsecure:

ws://{api-gateway}/api/ws/events/v1

Headers

Key Description
Authorization
(optional)
string
An IDP token in bearer format: Bearer {token}

Example: Bearer eyJhbG...ZGhCy4rg

NOTE:
If the Authorization header is not provided, authentication must be done by means of the Authenticate command. See below.

Messages

The messages are JSON formatted Events and State commands.

NOTE:
In case of malformed commands then the connection will be closed.

Responses

Most common HTTP responses

Status Description
101 Upgrading to a WebSockets connection (Connection succeeded).
401 Unauthorized access, expired or missing authorization token.
500 Internal server error, generic error has occurred on the server.
503 Service unavailable, the server is temporarily unavailable.

Authenticate Command

The authenticate command is an alternative to an Authorization header when establishing the WebSocket connection. It can be used to authenticate the connection after it has been established.

Functionality:

  • The command must be sent within the authenticate timeout time after connecting (default is 5 seconds).
  • It must be the first command sent after connecting.
  • In any other case the connection will be closed by the server.
{
    "command": "authenticate",
    "commandId": 1,
    "token": ""
}
Key Type Description
command string authenticate
commandId integer Id of the command. Generated by the client. The id should be unique for each command, since this id is used for the command response. It is however the responsibility of the client, and is not checked server side.
token string string
An IDP token in bearer format: Bearer {token}

Example: Bearer eyJhbG...ZGhCy4rg

Authenticate Response

Success

{
    "commandId": 1,
    "subscriptionId": "",
    "status": 200
}

Client is already authenticated

{
    "commandId": 1,
    "status": 409,
    "error": 
    {
        "errorText" : "Client is already authenticated."
    }
}

If validation fails:

| Close Status | Close Description | Description | | ------ | ----------- | | 1002 (Protocol Error) | No Authorization message received within the timeout period.|Connection timed out | 1008 (Policy Violation) | Unauthorized Access. |The provided token is invalid.| | 1008 (Policy Violation) | Expected Authenticate message. |First message after connection was not an Authenticate command.|

Events and State commands

Start Session Command

Once a client has established a connection it should either initiate a new session or attempt to resume an existing session.

Functionality:

  • A client must start a session before any other commands can be accepted on the connection.
  • A session can only be associated with one client (connection).
  • Resuming a session can only be done by the same user (identified by means of the bearer token when connecting) that initially created the session.
  • A session must be resumed within the lifetime defined for an inactive session (default is 30 seconds), otherwise it will be removed from the server. The lifetime currently used is provided as part of the �Start Session Response� message. The lifetime can be changed by modifying the EssResumeSessionTimeout parameter defined in the Event Server configuration file (VideoOS.Event.Server.exe.config).
  • If an unknown session id is provided, the session is expired, the EventID is unknown or the EventId is expired, a new session will be created.
{
    "command": "startSession",
    "commandId": 1,
    "sessionId": "",
    "eventId": ""
}
Key Type Description
command string startSession
commandId integer Id of the command. Generated by the client. The id should be unique for each command, since this id is used for the command response. It is however the responsibility of the client, and is not checked server side.
sessionId string Empty when a new session should be initiated. When specifying a valid GUID then an existing session having this id should be resumed.
eventId string Id of the last event that has been successfully received. This field is ignored when creating a new session. When resuming a session and specifying this id, the server will send all events that have occurred after this last received event. To ignore cached events this should be empty.

Examples

Sample 1 - Create a new Session

{
    "command": "startSession",
    "commandId": 1,
    "sessionId": "",
    "eventId": ""
}

Sample 2 - Resume an existing Session, getting no cached events

{
    "command": "startSession",
    "commandId": 2,
    "sessionId": "991FE95D-98FB-47EF-8A6E-635A184FBDBE",
    "eventId": ""
}

Sample 3 - Resume an existing Session, requesting cached events

{
    "command": "startSession",
    "commandId": 3,
    "sessionId": "991FE95D-98FB-47EF-8A6E-635A184FBDBE",
    "eventId": "381F3948-AD23-4E88-840D-10BB61B4B3C2"
}

Start Session Response

Success

{
    "commandId": 1,
    "sessionId": "",
    "inactiveTimeoutSeconds": 30
    "status": 200
}
Key Type Description
commandId integer Id of the command that has been responded to.
sessionId string Id of the session that has been created or resumed.
inactiveTimeoutSeconds integer Number of seconds defining the lifetime of an inactive session.
status integer 200 when a session has been resumed, 201 when a new session has been created.

Examples

Sample 1 - New session has been created

{
    "commandId": 1,
    "sessionId": "D129A5A0-BCF6-46C5-862D-C57F188DE369",
    "inactiveTimeoutSeconds": 30
    "status": 201
}

Sample 2 - An existing session has been resumed

{
    "commandId": 2,
    "sessionId": "991FE95D-98FB-47EF-8A6E-635A184FBDBE",
    "inactiveTimeoutSeconds": 30
    "status": 200
}

Sample 3 - Resuming an existing session failed - a new session has been created instead

{
    "commandId": 3,
    "sessionId": "1B73F389-6E73-4FE2-BE35-2547A778CE15",
    "inactiveTimeoutSeconds": 30
    "status": 201
}

Failure

{
    "commandId": 1,
    "status": 400,
    "error": 
    {
        "errorText" : ""
    }
}
Key Type Description
commandId integer Id of the command that has been responded to.
status integer HTTP error code stating the cause of the error.
errorText string Text describing the error.

An error response will be returned if a session does not exist, if other commands are sent to the server, or if the command has malformed values.

Add Subscription Command

To receive events a subscription must be made defining the events of interest. The subscription defines which event types, sources and resources that should be used for filtering the events that are raised in the VMS and should be pushed to the client. Use the addSubscription command to apply a subscription.

Functionality:

  • A session must be established (startSession command) before this command can be sent.
  • A client can create multiple subscriptions.
  • Individual subscriptions do not affect each other. I.e., events included in one subscription cannot be effectively excluded by another subscription.
  • An event that is included in multiple subscriptions it will only be sent to the client once.
{
    "command": "addSubscription",
    "commandId": 1,
    "filters": [
        {
            "modifier": "",
            "resourceTypes": [],
            "sourceIds": [],
            "eventTypes": []
        }
    ]
}
Key Type Description
command string addSubscription
commandId integer Id of the command. Generated by the client. The id should be unique for each command, since this id is used for the command response. It is however the responsibility of the client, and is not checked server side.
filters array of objects List of filters that includes and excludes events. By default no events are included. The list MUST contain at least one filter that has the include modifier.

Filter content

Key Type Description
modifier string include or exclude controls whether the events specified in the filter are included or excluded. Exclude modifiers has higher priority than Include modifiers. I.e. if an event is in anyway excluded by means of any exclude-filter it cannot be included by an include-filter. Thus one should be careful using * in exclude-filters.
resourceTypes array of strings A "*" (a list containing only this element) or a list defining resource types represented by strings and GUIDs. E.g. "cameras", "microphones", GUID representing a resource type. The strings are case insensitive and known by the system. If any of the strings does not match a known resource type, the subscription will fail, and an error response is returned.
sourceIds array of strings A "*" or a list of GUIDs that represents source that produced the event.
eventTypes array of strings A "*" (a list containing only this element) or a list of GUIDs that represents event type(s). E.g. a GUID representing ArchiveFailure, or a GUID representing DiskFull.

NOTE:
When defining a "*" in an array, then it MUST be the only element. When defining GUIDs these must be strings that can be parsed as GUIDs. Any valid GUID is accepted, however it is not validated whether it is known by the VMS.

Add Subscription Response

Success

{
    "commandId": 1,
    "subscriptionId": "",
    "status": 200
}
Key Type Description
commandId integer Id of the command that has been responded to.
subscriptionId string Id of the subscription, created by the server.
status integer 200 when a new subscription has been added.

Failure

{
    "commandId": 1,
    "status": 400,
    "error": 
    {
        "errorText" : ""
    }
}
Key Type Description
commandId integer Id of the command that has been responded to.
status integer HTTP error code stating the cause of the error.
errorText string Text describing the error.

Remove Subscription Command

{
    "command": "removeSubscription",
    "commandId": 1,
    "subscriptionId": "",
}
Key Type Description
command string removeSubscription
commandId integer Id of the command. Generated by the client. The id should be unique for each command, since this id is used for the command response. It is however the responsibility of the client, and is not checked server side.
subscriptionId string This must be the id received as a response to a previous addSubscription command. If the subscription does not exist, the server will respond with an error.

Remove Subscription Response

Success

{
    "commandId": 1,
    "status": 200
}
Key Type Description
commandId integer Id of the command that has been responded to.
status integer 200 when a new subscription has been added.

Failure

{
    "commandId": 1,
    "status": 400,
    "error": 
    {
        "errorText" : ""
    }
}
Key Type Description
commandId integer Id of the command that has been responded to.
status integer HTTP error code stating the cause of the error.
errorText string Text describing the error.

Get State Command

The getState command can be used to get the current state based on the stateful events that have been subscribed for. It can be sent at any point in time during a session to resynchronize the states that a client may depend on.

Functionality:

  • If the result of the subscription is nothing, then no states will be returned.
  • States can only be provided for stateful events, which have a stategroupid.
  • A state is returned if a subscription is made to any of the events that are part of the state group AND the state is actually known at the time of the query.

Example: If the subscription defines types A and B, but the current state has event type C, then state C is returned, event though the client will not receive the event that the state has changed to this value. For this reason, it is recommended to subscribe to all event types within a state group.

{
    "command": "getState",
    "commandId": 1
}
Key Type Description
command string getState
commandId integer Id of the command. Generated by the client. The id should be unique for each command, since this id is used for the command response. It is however the responsibility of the client, and is not checked server side.

Get State Response

Success

{
    "commandId": 1,
    "status": 200,
    "states": [
        {
            "specVersion": "1.0",
            "type": "",
            "source": "",
            "time": "",
            "stategroupid": ""
        }
    ]
}
Key Type Description
commandId integer Id of the command that has been responded to.
status integer 200 when a new subscription has been added.
states array List of states based on the defined subscriptions and the known state at the time of the query.

States content

Key Type Description
specVersion string 1.0 (constant) version of the event structure
type string Event Type, a GUID that represents an event. E.g. "DiskFull", "Recording Started" etc.
source string Format [resource path]/[GUID]. Identifying the source of the event in the VMS. The resource path refers to the type of hardware. The GUID uniquely identifies the hardware. Example: cameras/2313e29f-0a10-4463-9ce5-345e143d87c0
time string (date-time UTC) Format: "yyyy-MM-ddTHH:mm:ss.fffffffZ". Indicates when the item entered the current state. The given timestamp indicates when the state was discovered. The item may have had this state for a longer time since the timestamp may indicate the time when the Event Server was started and collected the state from the system.
stategroupid string GUID that identifies the state group that the event belongs to.

Events

Events and states are received in event messages. The event messages are sent soonest possible after an event has been detected in the VMS. An event message can contain one or more events. The events in the event message are formatted according to the cloudevents specification JSON Event Format for CloudEvents and are following the JSON Scheme CloudEvents.

Order of events

Events in an event message is ordered in the same order as the events were detected. Events messages are sent in the order that their contained events were detected.

I.e., when receiving an event message containing events A,B and subsequently receiving an event message containing events C,D, means that the events are detected in the order A,B,C,D.

Thus, when receiving stateful events, it is safe to assume that the last received event also reflects the current state in the VMS.

Format

{
    "events": [
        {
            "specversion": "",
            "type": "",
            "source": "",
            "id": "",
            "time": "",
            "stategroupid": "",
            "data": {}
        },
        {}
    ]
}
Key Type Description
specversion string Version of the event format
type string GUID representing the event type in the VMS
source string Format [resource path]/[GUID]. Identifying the source of the event in the VMS
id string Unique ID of the event. Note this field may contain an empty GUID (00...) in rare cases where the event reflects a detected state that is not caused by an underlying stateful event.
time string (date-time UTC) The time when the event was detected
stategroupid string The field is not mandatory. If present the event is stateful, and this ID defines the state group the event belongs to.
data object This field may contain additional data. The content depends on the type of the event.

Example

{
    "events": [
        {
            "specversion": "1.0",
            "type": "698ef3b8-9545-4f7e-8c1f-2e4056c10f78",
            "source": "cameras/11979584-2dab-496f-a8c2-527b1922da66",
            "id": "4577f552-765a-438c-bc7d-e5ff1f754bc3",
            "time": "2023-03-13T14:22:58.7379497Z",
            "data": {
                "description": "a nice description",
                "startTime": "2023-03-13T14:22:58.7379497Z",
                "endTime": "2023-03-13T14:22:58.7379497Z",
                "location": "Copenhagen",
                "count": 1,
                "rules": [
                    {
                        "id": "cce6ee25-e43e-4c9e-8b85-f93e379a842d"
                    }
                ],
                "objects": [
                    {
                        "id": "d9d9facb-dfdf-4517-85d8-1b1d3f09c95b",
                        "confidence": 0.0,
                        "alarmTrigger": false,
                        "removed": false,
                        "size": 0.0
                    }
                ],
                "references": [
                    "cameras/11979584-2dab-496f-a8c2-527b1922da66"
                ],
                "vendor": {
                    "name": "vendor 1"
                }
            }
        }
    ]
}

Events and State WebSocket API Sequence diagram

Event and State WebSocket API sequence diagram

Sequence diagram showing:

  • Normal setup: Establishing connection, starting a session, adding a subscription, receiving events and calling getState to receive stateful events.
  • Disconnects: Re-establishing connection, resuming session from last received event and receiving events

NOTE:
If resuming the session is not possible, due to for example exceeding timeout, the start session response will include a new session id and the status code 201 signaling a new session has been created.

MIP VMS API