Skip to main content

WebSockets

Subspace is a read-only API that allows your system to recieve streaming real-time information about changes to your Appointments, Warehouses, Docks, etc.

Using Subspace you can implement a "push"-based approach to your integration instead of relying only on "poll"-ing methods (which can be inefficient).

Subpsace is based on the famous socket.io library.

Choosing a socket.io Client

The socket.io project provides a JavaScript client library that works in the browser as well as NodeJS. However there are also client implementations in many other languages including C#, Java, Python, and Go, so you should select the appropriate client for your project. A good overview of socket.io and a list of client implementations can be found here: Socket.IO Introduction

warning

Currently Opendock uses socket.io server v4.x so please make sure to select an appropriate socket.io client version that is protocol compatible.

Connecting and Authentication

The base connection URL is the same as the base URL for Neutron above, except with the word "subspace" instead of " neutron". For example, our production Subspace connection URL is wss://subspace.opendock.com.

For convenience, the same JWT token obtained from the Neutron /auth/login endpoint above is used for Subspace authentication.

Connecting and Authenticating are done in a single operation: simply connect to the following wss URL:

<Connection URL>?token=<JWT Token>

That can be a little confusing to parse. Here's a real-life example connection string:

wss://subspace.opendock.com?token=eyJhbGciOiJIUzI1Ni...(full token continues)
info

Currently Opendock only supports the websocket transport, so you must specify this in your connection settings.

Here's an example of connecting to Subspace using the JavaScript client:

// NOTE: we assume "accessToken" was already obtained earlier via a call to '/auth/login'.
const baseSubspaceUrl = 'wss://subspace.opendock.com';
const url = `${baseSubspaceUrl}?token=${accessToken}`;
const socket = io(url, { transports: ['websocket'] }); // Enforce 'websocket' transport only.

Listening to events

Subspace emits Create/Update/Delete events for each entity in your Org (Appointment, Warehouse, Dock, etc). Your event handler for these events will receive a JSON object containing the details about the given entity.

Once your socket.io client instance is connected, you can listen for any of these events by constructing the appropriate event string:

Event strings follow this pattern:

"{EventType}-{EntityName}"

EventType can be one of: create, update, or delete.

EntityName can be any entity in our REST API, such as: Appointment, Warehouse, Dock, etc.

So for example, to listen to create events for Appointment entities you would use:

"create-Appointment"

Or to listen to update events for Warehouse entities you would use:

"update-Warehouse"

NOTE: The event types are lowercase, but the entity names are capitalized (event strings are case-sensitive).

There is also a "heartbeat" event that you can listen to, which will emit every 5 seconds with a timestamp and the Neutron API version. This can be helpful for ensuring that your connection to Subspace is working correctly.

Caveats and Limitations

Subspace does not do any sort of "catch-up" or "replay" of events, you will only get the events that occur after you connect to the socket.io server.

If your client loses connection for some time, the event messages will not be queued and delivered when you next connect, you will simply start receiving new messages after the point in time that you connected.

For this reason, even when using Subspace, you may need to occasionally supplement with calls to our REST API (ie. getAll) to fetch entities and keep in sync with the data in Opendock, depending on your needs.

Examples

Listening for Heartbeat

This event handler will get called periodically with the "heartbeat" information:

socket.on('heartbeat', (data) => {
console.log(data);
});

This will output something like:

{
now: '2022-09-15T20:02:20.015Z',
version: {
major: '2',
minor: '5',
patch: '16',
commit: '4a443fb\n'
}
}

Listening for Appointment Creation and Update

In this example, your event handler will get called whenever an Appointment is created in your Org:

socket.on('create-Appointment', (data) => {
console.log('appt create:', data);
});

The data your event handler recieves will be a JSON object containing the Appointment details, like this:

{
"id": "9cd63603-a7ff-43c7-8183-befc19a7a81b",
"createDateTime": "2022-07-29T06:49:20Z",
"lastChangedDateTime": "2022-07-29T06:49:20Z",
"isActive": true,
"tags": [],
"type": "Standard",
"status": "Scheduled",
"start": "2022-07-29T00:00:00+00:00",
"end": "2022-07-29T01:30:00+00:00",
...
...
...
}

If you also wanted to listen for any changes to existing Appointments you could add another listener:

socket.on('create-Appointment', (data) => {
console.log('appt create:', data);
});

socket.on('update-Appointment', (data) => {
console.log('appt update:', data);
});

The update-Appointment event handler will receive a similar JSON object containing the most up-to-date details of the Appointment that was just updated.