Using the WebSockets Messaging API, you can publish and subscribe to messages sent across clients, servers and standalone services. To get started quickly with the WebSockets Messaging API, refer to our comprehensive quickstart quide. To write your own protocol integration, dive into the full API reference.
⚠️ The WebSockets Messaging API is currently in beta version. Future releases of this API might break backwards compatibility.
A topic is like a channel where clients to which clients can publish, subscribe and receive messages from. Each topic is identified by a string. All clients subscribed to a topic receive all messages published to the topic. If you subscribe and publish to a topic, you will also receive your own messages.
⚠️ You should use unique topics to avoid collisions with other plugins. You may use uuids or the following format:
company-name.plugin-name.message-name
.
To use the WebSockets Messaging API, you must have:
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. If you don't have one, go to Create basic users.
⚠️ User credentials, bearer tokens, and other sensitive data are transmitted in cleartext if you do not set up certificates and use HTTPS. Make sure that your XProtect system is set up with HTTPS in production.
Follow this quickstart guide to publish and subscribe to messages with C#.
Verify the requirements
Check the initial Requirements.
Check out the samples
Clone the repository from GitHub and open PluginSamples.sln with your Visual Studio. The relevant project is ChatWithWebsockets.cproj
Follow this quickstart guide to publish and subscribe to messages with JavaScript.
Verify the requirements
Check the initial Requirements.
Check out the samples
Clone the repository from GitHub and open index.html with your browser.
Connect to the message communication service to start sending and receiving messages. To connect, start a secure WebSockets connection at wss://{api-gateway}/api/ws/messages/v1
.
If you don't have certificates enabled, you can only use the unsecure endpoint:
ws://{api-gateway}/api/ws/messages/v1
.
If you had established a connection but it broke, reconnect using the sessionId
and lastSeq
query parameters.
wss://test-01.example.com/api/ws/messages/v1?sessionId=359b13ac-2aa9-4924-8103-6bba01fecc19&lastSeq=123
Key | Description |
---|---|
Authorization | string (required) An IDP token in bearer format: Bearer {token} Example: Bearer eyJhbG...ZGhCy4rg |
If you cannot set the Authorization header, you can also authenticate with the Auth command.
Key | Description |
---|---|
sessionId | uuid4 The id of the session that you received after connecting (see Hello). Use it to resume a session and receive all messages sent while you were not connected (up to a configurable time). Example: 359b13ac-2aa9-4924-8103-6bba01fecc19 |
lastSeq | int The sequence number of the last message you processed. Use it to resume a session and receive all messages sent after the last one you processed (up to a configurable time). lastSeq must be greater or equal than the seq value you sent in the last Pulse. Example: 123 |
Status | Description |
---|---|
101 | Upgrading to a websockets connection. |
401 | Invalid, expired or missing authorization token. |
400 | Invalid or expired session (messages cannot be recovered). |
When you connect to the messaging service, a session is automatically initiated. You can disconnect from the service momentarily and reconnect using the same session id to recover all messages sent while you were offline.
Use sessions to handle both regular, forced and unexpected reconnections without loosing messages:
You should expect disconnects to happen normally and be ready to handle them.
sessionId
and pulsePeriodSeconds
.pulsePeriodSeconds
seconds.seq
of the last processed message.The pulsePeriodSeconds
is 15 seconds by default. Messages are preserved for up to 2 times the pulse period, and discarded after that if no successful reconnection attempt is performed.
A forced disconnect
happens if you don't send a pulse command or you have not acknowledged old messages.
You can configure the pulse period in the Event Server configuration file. For manual testing (i.e. Postman) and debugging, it is useful to set it to a large value.
server → client
Session id and pulse period received.
The server will send you a hello command when the connection is successful. It contains important information about your connection:
pulsePeriodSeconds
to start sending Pulse commands immediately.{
"type": "hello.v1",
"body": {
"sessionId": "ecdad995-0869-49f7-a639-d47caa601f7f",
"pulsePeriodSeconds": 15
},
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
}
Key | Description |
---|---|
type | hello.v1 |
Key | Description |
---|---|
sessionId | uuid4 (required) The identifier of the Session. Use it to reconnect without losing messages. Example: ecdad995-0869-49f7-a639-d47caa601f7f |
pulsePeriodSeconds | int (required) The period (in seconds) in which you MUST send Pulse commands. Example: 15 |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
server → client
A command has been successfully processed by the server.
The server will answer every valid command you send with an ack command. Use it to make sure you have published, subscribed or unsubscribed successfully.
☑️ Due to the TCP timeout, it can be tricky to know whether a command was successfully processed before an eventual network connectivity issue. The ack command makes it easier for you.
{
"type": "ack.v1",
"body": {
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
},
"id": "2aa04c78-15b0-49dc-967c-924b22deb25d"
}
Key | Description |
---|---|
type | ack.v1 |
Key | Description |
---|---|
id | uuid4 (required) The identifier of a command you sent. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 2aa04c78-15b0-49dc-967c-924b22deb25d |
server → client
A new message has been published in a topic you are subscribed to.
When another client publishes a message to a topic you are subscribed to, you receive a message command.
{
"type": "msg.v1",
"body": {
"seq": 123,
"topic": "my-company.my-plugin.my-topic",
"data": {
"someKey": "someValue",
"anotherKey": [1, 2, 3, 4],
"yetAnotherKey": {
"for": "this value"
}
}
},
"id": "2aa04c78-15b0-49dc-967c-924b22deb25d"
}
Key | Description |
---|---|
type | msg.v1 |
Key | Description |
---|---|
seq | int (required) The sequence number of the message. Store the largest sequence number you have processed and send it in the next Pulse. Example: 123 |
topic | string (required) The identifier of the Topic where the message was published. Use it when you are subscribed to more than one topic to understand the origin of each message. Example: my-company.my-plugin.my-topic |
data | object? An arbitrary JSON object, the payload of your message. Example: {} |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 2aa04c78-15b0-49dc-967c-924b22deb25d |
client → server
Acknowledge received messages.
You MUST send period pulse commands to the server periodically every pulsePeriodSeconds seconds.
⚠️ If you do not send pulse commands acknowledging messages every
pulsePeriodSeconds
, the server will terminate your connection.
You can configure the pulse period in the Event Server configuration file. For manual testing (i.e. Postman) and debugging, it is useful to set it to a large value.
{
"type": "pulse.v1",
"body": {
"seq": 123
},
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
}
Key | Description |
---|---|
type | pulse.v1 |
Key | Description |
---|---|
seq | int (required) The seq value of the last Message you have received and processed. If you have not received any messages yet, send -1 . Example: 123 |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
client → server
Send a message to all clients subscribed to a topic.
Use the publish command to send a message to a topic. The message can contain any arbitrary JSON payload.
⚠️ You should use unique topics to avoid collisions with other plugins. You may use uuids or the following format:
company-name.plugin-name.message-name
.
{
"type": "pub.v1",
"body": {
"topic": "my-company.my-plugin.my-topic",
"data": {
"someKey": "someValue",
"anotherKey": [1, 2, 3, 4],
"yetAnotherKey": {
"for": "this value"
}
}
},
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
}
Key | Description |
---|---|
type | pub.v1 |
Key | Description |
---|---|
topic | string (required) The identifier of the Topic you want to publish the message in. All clients subscribed to this topic will receive your message, except yourself. Example: my-company.my-plugin.my-topic |
data | object? An arbitrary JSON object, the payload of your message. Example: {} |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
client → server
Subscribe to all messages published to a topic.
Use the subscribe command to receive all messages that are published to a topic by other clients. The subscribe operation is idempotent.
{
"type": "sub.v1",
"body": {
"topic": "my-company.my-plugin.my-topic"
},
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
}
Key | Description |
---|---|
type | sub.v1 |
Key | Description |
---|---|
topic | string (required) The identifier of the Topic you want to receive messages from. Example: my-company.my-plugin.my-topic |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
client → server
Unsubscribe from a topic.
Use the unsubscribe command to stop receiving messages that are published to a topic. The unsubscribe operation is idempotent.
{
"type": "unsub.v1",
"body": {
"topic": "my-company.my-plugin.my-topic"
},
"id": "3a564ea5-ef64-4215-9eba-9384f37489a6"
}
Key | Description |
---|---|
type | unsub.v1 |
Key | Description |
---|---|
topic | string (required) The identifier of the Topic you want to stop receiving messages from. Example: my-company.my-plugin.my-topic |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
server → client
An invalid command or forced disconnect occurred.
Use the error command during debugging and developing to troubleshoot issues.
If you send an invalid JSON object, the error command will not be issued. These errors are only logged in the server.
{
"id": "7c5737a9-fb5e-4dda-8028-5ad30e1e54be",
"type": "error.v1",
"body": {
"description": "No commands have been sent for more than the allowed pulse period or no pulse has been sent to acknowledge received messages",
"invalidCommandId": null
}
}
Key | Description |
---|---|
type | error.v1 |
Key | Description |
---|---|
description | string (required) A description of the error. Example: No commands have been sent for more than the allowed pulse period or no pulse has been sent to acknowledge received messages |
invalidCommandId | uuid The id of invalid command. Example: 10bcd57a-7e57-446c-a31b-8eb1417fac09 |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |
client → server
Authenticate inside the channel.
Use the auth command to authenticate when you cannot set the Authorization header. For example, when you are using the browser WebSocket client.
If you send any other commands before authenticating, either through the headers or the auth command, your session will be automatically terminated.
{
"id": "7c5737a9-fb5e-4dda-8028-5ad30e1e54be",
"type": "auth.v1",
"body": {
"token": "Bearer eyJhbG...ZGhCy4rg"
}
}
Key | Description |
---|---|
type | auth.v1 |
Key | Description |
---|---|
token | string (required) A token in Bearer format issued by IDP. |
Key | Description |
---|---|
id | uuid4 (required) A unique identifier of the command. Example: 3a564ea5-ef64-4215-9eba-9384f37489a6 |