This documentation is old. Please visit the new documentation pages at docs.layer.com

WebSocket API

The WebSocket API provides a connection through which real time events can be received, allowing clients to receive Messages, metadata and read receipts in real time.

The WebSocket API also supports a number of operations such as sending Messages and creating Conversations.

Establishing a WebSocket connection requires a Session Token. While a WebSocket connection can be created from any type of client, this document uses a JavaScript client for all examples.

Clients open a WebSocket connection with an HTTPS request on the /websocket endpoint with an upgrade request following the WebSocket protocol. The subprotocol layer-1.0 is required for this connection. The Layer session token can be sent either in the Authorization header or in the URL's query string.

The JavaScript WebSocket object handles the upgrade handshake, allowing for the following initialization:

var ws = new WebSocket('wss://websockets.layer.com/?session_token=keuIjkPoPlkxw==',
    'layer-1.0');
ws.addEventListener('message', myMessageHandler);

Packet Structure

To avoid confusion with Layer messages, events and notifications, we use the term Packet to describe messages received through the WebSocket.

Packets have a standard set of top-level fields described below.

Field Description
type change, request, response, signal
timestamp The server timestamp of the notification.
body The details of the request being made
counter WebSocket index; used for detecting missed packets.

Packets will be named by the type field in this document:

  • Change Packet: Reports on resources that have changed on the server
  • Request Packet: The client sends this to request an operation from the server
  • Response Packet: The server sends this in response to a Request Packet
  • Signal Packet: An ephemeral event such as typing indicator is sent to or from the server

Managing a Websocket

Websockets can close for a variety of reasons, caused by the client, the network or the server. You should be prepared to create a new websocket when the old one closes. When your session-token is either deleted or expired, the websocket session will automatically close as well.

On reopenning a websocket, you can catch up on missed events.

Sample Code

For sample code, visit the Layer for Web Sample Code repo on Github.

Change Packets

The WebSocket API will notify you of any and all changes on the server to resources that the authenticated user has permission to view.

Changes may include creating, deleting or updating of Messages and Conversations. The Change Packets will provide all of the data needed to keep your local copy in sync with the server copy of this data.

It is not necessary for an application to use all of these events to maintain state. New Messages in Conversations that your user is not currently using may not be of interest; updates to Conversations that are not locally cached probably aren't of interest; etc... Ultimately, developers will need to evolve a strategy for:

  • Managing a cache of Messages, Announcements and Conversations that does not grow out of control
  • Deciding how to handle events on Messages, Announcements and Conversations that are not already cached (use the REST API to load them or ignore them)
  • Deciding whether to cache new objects that are not part of a currently open Conversation (cache them or ignore them).

Change packets have the following properties in the body field:

Field Description
operation create, delete, update
object The type and identifier of the object being operated upon.
data Details of the change that was performed on the server.

The object Field

The object field is used to identify the object that the Packet relates to.

Field Description
type Type of Object: Conversation, Announcement, Message
id The Layer ID of the Object: "layer:///conversations/uuid"
url URL to the specified Object

When the server is sending a Change Packet to the client, the Object will look like:

{
  "object": {
    "type": "Conversation",
    "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
    "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
  }
}

Create Events

A Change Packet containing a create event is received whenever the server receives a new Message or Conversation. Note that you will receive these not just for new Messages and Conversations created by others, but also by yourself. The data field will contain the full Conversation or Message object.

{
  "type": "change",
  "counter": 6,
  "timestamp": "2014-09-15T04:45:00+00:00",
  "body": {
    "operation": "create",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data": <Conversation>
  }
}
{
  "type": "change",
  "counter": 7,
  "timestamp": "2014-09-15T04:45:00+00:00",
  "body": {
    "operation": "create",
    "object": {
      "type": "Message",
      "id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df68",
      "url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df68"
    },
    "data": <Message>
  }
}
{
  "type": "change",
  "counter": 7,
  "timestamp": "2014-09-15T04:45:00+00:00",
  "body": {
    "operation": "create",
    "object": {
      "type": "Announcement",
      "id": "layer:///announcements/f3cc7b32-3c92-11e4-baad-164230d1df68",
      "url": "https://api.layer.com/announcements/f3cc7b32-3c92-11e4-baad-164230d1df68"
    },
    "data": <Announcement>
  }
}

Delete Events

A Change Packet containing a delete event is received whenever the server detects that a Message or Conversation has been deleted. Note that you will receive these not just for Messages and Conversations deleted by others, but also by yourself.

The data field will contain a mode field indicating if the deletion is for all_participants (deleted for all users) or my_devices (deleted for this user's account only); See DELETE Requests.

There are three types of Delete Events your app may encounter:

Delete for all_participants

Both Messages and Conversations can be deleted for all users; you know it is this type of deletion when the mode is all_participants.

 {
   "type": "change",
   "counter": 9,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Message",
       "id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df68",
       "url": "https://api.layer.com/messages/940de862-3c96-11e4-baad-164230d1df68"
     },
     "data": {
       "mode": "all_participants"
     }
   }
 }
 {
   "type": "change",
   "counter": 8,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Conversation",
       "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
       "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
     },
     "data": {
       "mode": "all_participants",
       "from_position": null
     }
   }
 }

Deleting for my_devices

Both Messages and Conversations can be deleted for this user only; you know it is this type of deletion when the mode is my_devices.

 {
   "type": "change",
   "counter": 9,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Message",
       "id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df68",
       "url": "https://api.layer.com/messages/940de862-3c96-11e4-baad-164230d1df68"
     },
     "data": {
       "mode": "my_devices"
     }
   }
 }
 {
   "type": "change",
   "counter": 8,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Conversation",
       "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
       "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
     },
     "data": {
       "mode": "my_devices",
       "from_position": null
     }
   }
 }

Deleting from_position

This last one is a special case of _Deleting for my_devices_ where the Conversation was deleted for all of the user's devices, but the user did not leave the Conversation. And then a New Message shows up causing the Conversation to be recreated for that user (see Leave Parameter in Delete). The from_position tells your app to delete all Messages whose position field are less than or equal to this value, and then do not delete the Conversation.

 {
   "type": "change",
   "counter": 8,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Conversation",
       "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
       "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
     },
     "data": {
       "mode": "my_devices",
       "from_position": 123456
     }
   }
 }

Deleting Announcements

Deletion mode does not apply to Announcements:

 {
   "type": "change",
   "counter": 9,
   "timestamp": "2015-01-19T09:15:43+00:00",
   "body": {
     "operation": "delete",
     "object": {
       "type": "Announcement",
       "id": "layer:///announcements/f3cc7b32-3c92-11e4-baad-164230d1df68",
       "url": "https://api.layer.com/announcements/940de862-3c96-11e4-baad-164230d1df68"
     },
     "data": {}
   }
 }

Expected actions by your App

Expected responses to a Deletion Event are the same for _Deleting for all_participants_ and _Deleting for my_devices_:

  1. Remove the object from your UI if you are rendering the object
  2. Remove the object from any data caches/data stores

Expected response to _Deleting from_position_:

  1. Delete all messages in the Conversation whose position is less than or equal to the from_position value from your UI and stores.
  2. Do NOT delete the Conversation

Update Events

A Change Packet containing an update event is received whenever the server detects that a Message or Conversation has been changed. Note that you will receive these not just for Messages and Conversations changed by others, but also by yourself.

The data field will contain an array of layer-patch operations that specify the changes to make to the object.

The Layer Patch Operations Array is documented in the Layer Patch Spec; that repo also contains a JavaScript library for working with Layer Patch operations.

The following properties can be updated via an Update Event:

  • Conversation.participants: participants can be added or removed
  • Conversation.metadata: Metadata keys can be set or deleted
  • Message.recipient_status: Recipient status is updated as delivery and read receipts are received
  • Conversation.last_message: The ID for the Message is provided each time a new Message becomes the most recent Message
  • Conversation.unread_message_count: Any time a Conversation's unread message count changes, you will be notified

Note that it is common to receive multiple Layer Patch Operations in a single Change Packet, resulting in multiple changes to a properties.

Add/Replace Participants Example

{
  "type": "change",
  "counter": 10,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "operation": "update",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data": [
      { "operation": "add",    "property": "participants", "value": "4567" },
      { "operation": "remove", "property": "participants", "value": "5678" }
    ]
  }
}

Update Metadata Example

{
  "type": "change",
  "counter": 11,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "operation": "update",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data" : [
      { "operation": "delete", "property": "metadata.a.b.c" },
      { "operation": "set",    "property": "metadata.a.b.name",  "value": "foo" },
      { "operation": "set",    "property": "metadata.a.b.count", "value": "42"  }
    ]
  }
}

Update Read/Delivery Status Example

{
  "type": "change",
  "counter": 12,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "operation": "update",
    "object": {
      "type": "Message",
      "id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/messages/940de862-3c96-11e4-baad-164230d1df67"
    },
    "data": [
      {
        "operation": "set",
        "property": "recipient_status.fred\.flinstone",
        "value": "delivered"
      }
    ]
  }
}

Note that if the property is "recipient_status.fred.flinstone", then it will try to set:

{
  "recipient_status": {
    "fred": {
      "flinstone": "delivered"
    }
  }
}

Whereas what is needed is: "recipient_status.fred\.flinstone" which will set:

{
  "recipient_status": {
    "fred.flinstone": "delivered"
  }
}

Announcements will also receive read receipts; especially useful if your user is logged into multiple devices:

{
  "type": "change",
  "counter": 12,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "operation": "update",
    "object": {
      "type": "Announcement",
      "id": "layer:///announcements/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/announcements/940de862-3c96-11e4-baad-164230d1df67"
    },
    "data": [
      {
        "operation": "set",
        "property": "recipient_status.FrodoTheDodo",
        "value": "read"
      }
    ]
  }
}

Update Last Message on a Conversation Example

{
  "type": "change",
  "counter": 13,
  "timestamp": "2014-09-15T04:45:00+00:00",
  "body": {
    "operation": "update",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data": [
      {
        "operation": "set",
        "property": "last_message",
        "id": "layer:///messages/940de862-3c96-11e4-baad-164230d1df67"
      }
    ]
  }
}

Note the use of id instead of value in this Layer Patch Operation; this is a hint that you may want to lookup the object and set the last_message property to the entire object.

Request Packets

The WebSocket API allows for a client to send requests to the server. While the long term goal is to support all REST API calls via the WebSocket, initially, only a few such requests are supported. There are also some WebSocket-Only requests that can be made (See Recovery).

Currently there only two requests supported (not counting those in Recovery):

  • Create a Message
  • Create a Conversation

There are two types of Packets that need to be understood for a complete transaction:

  • Request Packets
  • Response Packets

Request Packet Details

The body field of a Request Packet will have the following properties:

Field Type Description
request_id string An identifier created by the client to allow it to recognize a response
method string Message.create, Conversation.create
object_id string ID of the object the request concerns; optional
data object Each method defines what the data looks like

The request_id Field

When the client sends a Request Packet to the server, it can include an arbitrary string (containing letters, numbers, dashes, underscores and periods), that will be returned with a WebSocket response so that the response can be associated with the request. The Client is responsible for creating the string, which must match:

 /^[a-zA-Z0-9.-]+$/

If the request_id field is omitted, then the server will not send a Response Packet to the client.

A Response Packet will be sent to the client with the request_id provided in the request. If your requests need JavaScript callbacks to be invoked on receiving success/error responses, then this request_id is the only hint you have that a response is associated with a specific request and callback.

Response Packet Details

The body field of a Response Packet will have the following properties:

Field Type Description
request_id string Echos back the request_id sent by the client
method string Message.create, Conversation.create
data object Each method defines what the data looks like
success boolean true if the operation was a success; false if not

Create Requests

For all create calls, the fields to provide in the data field will match those documented in the REST API in Create a Conversation and Send a Message, and will not be documented here. There is one additional field of these requests: an id field where you specify what the ID of the object will be.

The responses generated by these will have a data field that either contains the object that was created, or an Error and described in Errors.

Create Message Example

The following request will attempt to create a message within a Conversation whose ID is layer:///conversations/e67b5da2-95ca-40c4-bfc5-a2a8baaeb50f:

{
  "type": "request",
  "body": {
    "method": "Message.create",
    "request_id": "fred.flinstone.3",
    "object_id": "layer:///conversations/e67b5da2-95ca-40c4-bfc5-a2a8baaeb50f",
    "data": {
      "parts": [
        {
          "mime_type": "text/plain",
          "body": "This is the message."
        },
        {
          "mime_type": "image/png",
          "content": {
            "id": "layer:///content/7a0aefb8-3c97-11e4-baad-164230d1df67",
            "size": 172114124
          }
        }
      ],
      "notification": {
        "title": "On the beach",
        "text": "All rise, its a Message!",
        "sound": "salute.aiff"
      }
    }
  }
}

Notification objects can be created using the notificaton customization definition that can be found at: Push Notifications. The following are possible responses:

ERROR:

{
  "type": "response",
  "counter": 18,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "request_id": "fred.flinstone.3",
    "method": "Message.create",
    "success": false,
    "data": {
      "code": 102,
      "id": "not_found",
      "message": "The Conversation could not be found.",
      "url": "http://api.layer.com/wtf"
    }
  }
}

SUCCESS:

{
  "type": "response",
  "counter": 16,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "request_id": "fred.flinstone.3",
    "method": "Message.create",
    "success": true,
    "data": <Message>
  }
}

Deduplication

When creating a resource, it is optional whether to include an id field. Doing so is useful for deduplication. A deduplication error typically indicates that the requested resource has already been created.

DEDUPLICATION ERROR:

{
  "type": "response",
  "counter": 18,
  "timestamp": "2015-01-19T09:15:43+00:00",
  "body": {
    "request_id": "fred.flinstone.3",
    "method": "Message.create",
    "success": false,
    "data": {
      "id": "id_in_use",
      "code": 111,
      "message": "The requested Message already exists",
      "url": "https://developer.layer.com/docs/client/websockets#create-requests",
      "data": <Message>
    }
  }
}

Typical usage by a Client of this id_in_use error is to report back to the caller that the Message/Conversation has been successfully created, delivering body.data.data which contains the Message/Conversation object to the caller. No further deduplication retries are needed at this point.

Typing Indicators

Typing Indicators are sent and received using Signal Packets.

The body field of a Signal Packet will contain the following fields:

Field Description
type The type of signal; "typing_indicator"
object For signals that relate to a specific object, an optional object field has been defined that matches the object field used in Create Packets. Required for typing indicators
request_id Optional field for use when a confirmation response is desired
data Custom data for the signal

Note that the object field when sent from the server should have id, url and type to match Change Packets. However, when the client sends these to the server, only id is needed.

The data field

A Typing indicator uses the data field to indicate typing status, and which user that status is associated with:

Field Description
user_id The identifier of the user whose typing state has changed
action "started", "paused", "finished"; the new state of the typing indicator for that user

Note that it is not required to send the user_id field when sending a typing indicator; this is automatically added by the server.

Receiving a Typing Indicator Example

{
 "type": "signal",
 "timestamp": "2015-01-19T09:15:43+00:00",
 "body": {
    "request_id": "fred.flinstone.95",
    "type": "typing_indicator",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/e67b5da2-95ca-40c4-bfc5-a2a8baaeb50f",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data": {
      "user_id": "12345",
      "action": "started"
    }
  }
}

Sending a Typing Indicator Example

{
 "type": "signal",
 "body": {
    "type": "typing_indicator",
    "request_id": "fred.flinstone.95",
    "object": {
      "id": "layer:///conversations/e67b5da2-95ca-40c4-bfc5-a2a8baaeb50f"
    },
    "data": {
      "action": "started"
    }
  }
}

Working with Typing Indicators

A client should update its typing indicator state every 2.5 seconds. As long as the application considers the user to be actively typing, it should resend "started" every 2.5 seconds. After a lag of no activity, "paused" should be sent, and should continue to be sent every 2.5 seconds. Once "finished" is sent, no further typing indicators need to be sent to the server until the state has changed.

Any failure to receive a state update from the client will cause the server to automatically transition to the next state. If "started" is sent to the server, and then no further states are sent, the server will automatically transition to "paused". If the state is "paused" and no states are sent by the client, it will transition to "finished".

Recovery

A lot can go wrong on a network. It could be as simple as a laptop going to sleep, a mobile phone going out of reception, or as ugly as DNS issues. Ultimately, connections are lost, change packets are missed, and apps need to recover and re-sync. The recovery tools provides three services:

  1. Detecting that an event has been missed
  2. Detecting that a connection is no longer alive and must be restarted
  3. Requesting missed events

Detecting Missed Events

Sketchy wifi or mobile connections can cause a connection to be lost and restored without any hint that a message was lost. Some browsers (Chrome in particular) will attempt to restore a connection rather than report a problem with the connection.

To insure that no events are missed, each event contains a counter. The counter is associated with the session rather than the event itself (thus we cannot request an event by its counter).

A given WebSocket connection will get an incrementing counter with each message it receives from the server. When a connection is established, the counter is set to 0. When a connection is recreated, its reset to 0. The first Packet will have a counter value of 0, the next message will have a counter value of 1, etc...

A client should expect to see the counter increment by one between each packet. If it ever increments by more than one, the client can see that it has missed events, and will request missed packets from the server. If it ever resets to zero, then the client knows that the connection was lost and reconnected automatically.

In the event that the counter has changed by a value other than +1, an Event.Replay request can be issued.

Monitoring Connection Health

JavaScript based WebSocket may not always detect that you have lost a connection. Chrome in particular will not detect that a WebSocket has lost a connection. As such, recommended practice is to send "ping" requests through the WebSocket every 30 seconds. Mobile devices and backgrounded tabs may chose to vary this recommendation to preserve battery life. If the WebSocket connection has been lost and you send a ping request, even Chrome will throw a connection error letting you know that there is a problem and that you may be failing to receive Change Packets.

A ping operation is done by sending a Counter.read request to the server. There are four possible outcomes of this request:

  1. The connection fails, and the WebSocket throws an error
    • Next Step: initiate reconnect logic, and catchup on missed events on reconnecting.
  2. The request fails to return a response (after waiting for 10 seconds, if there is no response, its safe to assume there is a problem).
    • Next Step: initiate reconnect logic, and catchup on missed events on reconnecting.
  3. A response containing a counter arrives; the counter is the same as the last packet from the server. All is well.
    • Next Step: none.
  4. A response containing a counter arrives; the counter has changed; this means Change Packets were probably missed.
    • Next Step: Catchup on missed events

Sending a Ping Request

The following simple script can be used to send the Ping request:

window.setInterval(function() {
    mysocket.send(JSON.stringify({
        "type": "request",
        "body": {
            "method": "Counter.read",
            "request_id": "fred.flinstone.31"
        }
    }));
}, 30000);

Connection Error Handling

If there is a connection problem, your ping request should cause the websocket to realize that and then trigger your onError handler. The following retry logic should continue to call your onError handler until you are back online. Varying the 15 seconds suggested below with some exponential backoff may make sense depending upon your environment.

Note that this error handler can fire due to your ping requests, but may also fire during the normal lifespan of your Websocket connection.

mysocket.addEventHandler("error", myErrorHandler);

function myErrorHandler(err) {
    // On Error: Wait 15 seconds and then create a new websocket
    window.setTimeout(function() {
        mysocket = new WebSocket('wss://websockets.layer.com/?session_token=donuts==',
                           'layer-1.0');

       // On successfully opening the websocket, replay missed events
       mysocket.addEventListener("open", function() {
            // How to implement this is described in the next section
            replayFrom(lastEvent.timestamp);
       });

       // Bind this new websocket's error handler to this handler
       mysocket.addEventHandler("error", myErrorHandler);
    }, 15000);
}

Note that if you do NOT have the ping request firing periodically, you may go hours without any Change Packets from the server, nor will there be any clue to your user that they are no longer connected to the server.

Using the Ping Response

The response to a ping will contain the current event counter. Note that the counter field will increment as a result of this response, but that the counter value returned in the data field will represent the state of the counter at the time of the request. This means:

  1. You will get back a counter field in the data object, and a second counter field in the high level response
  2. These two counters will always be different values (data reports on the counter of the last packet sent to the client, the response reports the counter associated with this response packet).
{
  "type": "response",
  "timestamp": "2015-01-19T09:15:43+00:00",
  "counter": 36,
  "body": {
    "request_id": "fred.flinstone.31",
    "method": "Counter.read",
    "data": {
      "counter": 35
    }
  }
}

The simplest way to use this response is to focus on the high level counter:

 ws.addEventListener('message', onMessage);
 var lastCounter = -1;
 function onMessage(evt) {
   var msg = JSON.parse(evt.data);
   var skippedCounter = lastCounter + 1 !== msg.counter;
   lastCounter = msg.counter;
   if (skippedCounter) replayEvents();
 }

This code snippet works regardless of whether the message received is a new Conversation, a read receipt, or the response to a Ping.

When Not to Ping

Ideally, pinging would not be done if any WebSocket messages have been recently received:

var intervalId;
var requestIDCounter = 0;
function restartPing() {
    if (intervalId) window.clearInterval(intervalId);
    intervalId = window.setInterval(function() {
        ws.send(JSON.stringify({
            "type": "request",
            "body": {
                "method": "Counter.read",
                "request_id": "fred.flinstone." + requestIDCounter++
            }
        }));
    }, 30000);
}

mysocket.addEventListener("message", function(evt) {
   restartPing();
});

Requesting Missed Events

A request can be sent to replay events. The result of this request will be to redeliver all Change Packets from the specified timestamp until the present, followed by a Response Packet.

The request involves the following parameters:

Field Description
from_timestamp The timestamp to replay events from.
{
  "type": "request",
  "body": {
    "method": "Event.replay",
    "request_id": "fred.flinstone.1003",
    "data": {
      "from_timestamp": "2014-09-09T04:44:47+00:00"
    }
  }
}

Note that when all events are replayed, some Change Packets you receive may have been previously received, and some care must be taken in processing these:

  • Processing a Create Packet should verify that you haven't already created the object
  • Processing a Delete Packet may find you've already deleted the object
  • Processing a Update Packet may result in no value change if you've previously received that event

When the replay has completed, the server will send the following Response Packet:

{
  "type": "response",
  "counter": 10053,
  "timestamp": "2014-09-09T04:54:47+00:00",
  "body": {
    "method": "Event.replay",
    "request_id": "fred.flinstone.1003",
    "success": true
  }
}