Protocol of the Real-Time State API

In order to retrieve and maintain data using the real-time state API, a certain protocol must be followed. The protocol is divided into four main parts, shown in order of execution:

  • Connection
    • The integration connects to the appliance via a secure connection.
  • Authentication
    • The integration sends credentials for authentication.
    • The server authenticates the credentials. The account used must have permission to use the real-time state API.
    • The server sends an authentication response to the integration.
  • Model Subscriptions
    • The integration subscribes to one or more tables in the model.
    • The server sends a full copy of the subscribed tables to the integration.
    • The integration is expected to maintain a copy of the tables.
  • Model Updates
    • The server pushes future updates of the subscribed tables to the integration.
    • The integration is expected to update its copy of the tables.

The connection, authentication, and model subscription phases are serial. All messages in those phases must be sent in the correct order, and all messages are required. Messages in the model updates phase can arrive in any order. Messages are encoded using JSON (JavaScript Object Notation), except for the connection phase.

The real-time state API has certain limits:

  • A maximum of thirty connected integrations may receive model updates simultaneously.
  • Connected integrations receive updates with a maximum latency of twenty seconds.
  • Integrations must have sufficient bandwidth to receive updates. Integrations that get too far behind the real-time stream are automatically disconnected.

IMPORTANT!

Information will be sent from the appliance within binary websocket messages, and data sent to the appliance can be sent within text websocket messages. Each message sent to or received from the appliance is terminated with a newline character (\n). It may be necessary to trim this character before parsing the JSON received. Similarly, a newline character must be appended to the end of all messages sent.

 

Connection

During the connection phase of the protocol, the integration makes a successful connection to the appliance. The steps below assume the integration is connecting over a web socket. Other socket types, such as TCP SSL sockets, can be supported but are not documented here.

Integration connects to the appliance using a secure web socket

  • new WebSocket ("wss://<hostname>/nw")

Note: Brackets should be removed from this and all examples below. E.g., new WebSocket ("wss://example.com/nw")

The nw tells the appliance that the integration is connecting over a web socket.

 

Integration sends appliance hello message

Integration → Appliance

  • NS01<company name>\ningredi state api\n

Note: Brackets should be removed from this and all examples below. E.g., NS01example\ningredi state api\n

The company name can be found by going to the /login > Status > Information page or by issuing the get_api_info command (see API Command: get_api_info).

 

Appliance sends integration response

Appliance → Integration

Successful response:

  • 0 Application chosen\n

Any other response is considered to be a failure.

 

Authentication

During the authentication phase of the protocol, the integration authenticates with the appliance.

Integration sends credentials to the appliance

Integration → Appliance

  • {
    • "type" : "authenticate",
    • "credentials" :
    • {
      • "bearer_token" : "<OAuth 2.0 bearer token>"

    • }
  • }\n

Only username and password authentication is supported.

 

Appliance verifies the credentials and sends an authentication response to the integration

Appliance → Integration

  • {
    • "type" : "authenticate_response",
    • "success" : true,
    • // or
    • // "success" : false,
    • "reason" : "reason if success == false"
  • }\n

After authenticating, the integration must subscribe to one or more tables in the model.

 

Model Subscriptions

During the model subscriptions phase of the protocol, the integration tells the appliance the parts of the system state model for which it wants to receive updates.

Integration subscribes to the model

Integration → Appliance

  • {
    • "type" : "subscribe",
    • "tables" : "all"
    • // or
    • // "tables" : ["customer_client", "..."]
  • }\n

The tables name/value pair can be either "all" to subscribe to all tables or an array of table names in the model. For a list and description of tables, see System State Model of the Real-Time API.

 

Appliance confirms the subscription

Appliance → Integration

  • {
    • "type" : "subscribe_response",
    • "timestamp" : <UNIX timestamp>,
    • "success" : true,
    • // or
    • // "success" : false,
    • "reason" : "reason if success == false"
  • }\n

In the subscribe response, the timestamp is the appliance's current time. This is useful for doing time calculations when the integration's clock is skewed from the appliance's clock.

After receiving the subscribe response, the integration starts to receive model updates from the appliance.

 

Model Updates

During the model updates phase of the protocol, the integration receives system state model updates from the appliance. The integration does not request model updates. Instead, model updates are sent automatically by the appliance as resources permit.

Note: If the appliance sends a large update, the data may be broken up multiple parts. Check to see if the message terminates with a newline character (\n). If it does not, append further messages until you receive a message ending with a newline, indicating you have reached the end of the data.

Update model message

Appliance → Integration

  • {
    • "type" : "model_update"
    • // "insert" is specified only if rows need to be inserted.
    • "insert" :
    • {
      • // One or more table names are specified as keys.
      • "<table>" :
      • {
        • // One or more row IDs are specified as keys.
        • "<id>" :
        • {
          • // One or more field names are specified as keys.
          • // Some fields in the table may not be listed.
          • "<field>" : "<value>",
          • // ...
        • },
        • // ...
      • },
      • // ...
    • },
    • // "update" is specified only if rows need to be updated
    • "update" :
    • {
      • // This object has the same syntax as "insert"
    • },
    • // "delete" is specified only if rows need to be deleted
    • "delete" :
    • {
      • // One or more table names are specified as keys.
      • // Each value is an array of row IDs to delete.
      • "<table>" : ["<id>", "<id>", ...],
      • // ...
    • },
  • }\n

At least one of insert, update, or delete will be specified, and a combination thereof could also be specified. When the message is received, the integration should update its copy of the state model:

  • For insert, the integration should insert into the specified <table>s a row for each given <id> and having the given <value>s for the specified <field>s.
  • For update, the integration should update existing rows for the given <table>s and the given <id>s, modifying them to have the given <value>s for the specified <field>s.
  • For delete, the integration should delete rows in the given <table>s with the given <id>s.

Truncate model message

Appliance → Integration

  • {
    • "type" : "truncate_model"
  • }\n

After receiving this message, the integration should delete all rows from all tables.