Real-time updates

Establish a WebSocket connection will allow to receive updates for changes from the server. Changes may include creating, deleting or updating of a Message and a Conversation. You will receive all packets, but you may choose to ignore some or even most of them depending on your use case.

Change packets have the following properties in the body field:

Field Type Description
operation string One of “create”, “delete” or “update”
object object The type and identifier of the object being operated upon.
data object 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 Type Description
type string Type of Object: Conversation, Message, MessagePart, Announcement, Identity
id string The Layer ID of the Object: layer:///conversations/uuid
url string 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 operations

A Change Packet containing a create operation is received whenever the server receives a new Message, Announcement, Conversation or Identity. You will receive these not just for new objects created by others, but also by yourself. The data field will contain the full 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
  }
}

Delete operations

A Change Packet containing a delete operation is received whenever the server detects that a Message, Announcement or Conversation has been deleted. You will receive these not just for objects deleted by others, but also objects deleted by yourself.

The data field will contain a mode field indicating if the deletion is for My Devices “my_devices” or for All Users “all_participants”; See Deleting.

{
  "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"
    }
  }
}
{
  "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"
    }
  }
}

Deleting from_position

A special case of Deleting a Conversation for “my_devices” occurs when you do this without Leaving the Conversation (url?leave=true&mode=my_devices): If a new Message is sent, the Conversation will be restored, with the Message history starting at that new Message. If this Message is sent at the same time as the Conversation being deleted, then the Conversation is never deleted and simply removes its Message history up to the point of the newly arrived Message. The from_position property 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
    }
  }
}

Update operations

A Change Packet containing an update operation is received whenever the server detects that a Message, Announcements or Conversation has been changed. You will receive these not just for objects changed by others, but also those changed by yourself.

The data field will contain an array of Layer-Patch operations that specify the changes to make to the object. The operations are 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
  • 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
  • Conversation.total_message_count: Any time a Conversation’s number of messages changes, you will be notified
  • Message.recipient_status: Recipient status is updated as delivery and read receipts are received
  • Message.parts: The message parts changed on the message (message edited) about which you will be notified
  • Message.updated_at: When a message gets edited updated_at on the message gets changed too, you will be notified when that happens
  • MessagePart.body: A notification is sent when the body property of a message part changes
  • MessagePart.mime_type: A notification is sent when the mime_type property of a message part changes
  • MessagePart.content: A notification is sent when the content property of a message part changes
  • MessagePart.encoding: A notification is sent when the encoding property of a message part changes
  • MessagePart.updated_at: A notification is sent when the updated_at property of a message part changes

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

Change 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", "id": "layer:///identities/4567", "value": BasicIdentity },
      { "operation": "remove", "property": "participants", "id": "layer:///identities/5678" }
    ]
  }
}

Change 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.layer:///identities/fred\.flinstone",
        "value": "delivered"
      }
    ]
  }
}

Note that if the property is recipient_status.layer:///identities/fred.flinstone, for example, then it will try to set:

{
  "recipient_status": {
    "layer:///identities/fred": {
      "flinstone": "delivered"
    }
  }
}

Instead, a property value of recipient_status.layer:///identities/fred\\.flinstone will set:

{
  "recipient_status": {
    "layer:///identities/fred.flinstone": "delivered"
  }
}

Update last message 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"
      }
    ]
  }
}

Add message part example:

{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "Message",
			"id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67"
		},
		"data": [{
				"operation": "add",
				"property": "parts",
        "id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
				"value": {
						"id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
						"url": "https://api.layer.com/messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
						"mime_type": "text/plain",
						"body": "This is the message.",
						"updated_at": "2017-05-15T18:05:09Z"
					}
			},
			{
				"operation": "set",
				"property": "updated_at",
				"value": "2014-09-15T04:44:59+00:00"
			}
		]
	}
}

Remove message part example:

{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "Message",
			"id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67"
		},
		"data": [{
				    "operation": "remove",
				    "property": "parts",
                    "id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7"
		        },
			    {
				    "operation": "set",
				    "property": "updated_at",
				    "value": "2014-09-15T04:44:59+00:00"
			    }
		]
	}
}

Update message part example:

Updating a message part means updating a message too, for this reason this operation produces two changes.

{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "MessagePart",
			"id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7"
		},
		"data": [
      {
				"operation": "set",
				"property": "body",
        "value": "This is an updated message"
			},
      {
				"operation": "set",
				"property": "mime_type",
        "value": "text/plain+updated"
			},
			{
				"operation": "set",
				"property": "updated_at",
				"value": "2014-09-15T04:44:59+00:00"
			}
		]
	}
}
{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "Message",
			"id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67"
		},
		"data": [
			{
				"operation": "set",
				"property": "updated_at",
				"value": "2014-09-15T04:44:59+00:00"
			}
		]
	}
}

Replace all message parts example:

{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "Message",
			"id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67"
		},
		"data": [{
                    "operation": "set",
                    "property": "parts",
                    "value": [
                        {
                            "id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
                            "url": "https://api.layer.com/messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7",
                            "mime_type": "text/plain",
                            "body": "This is the message.",
                            "updated_at": "2017-05-15T18:05:09Z"
                        },
                        {
                            "id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/776c6d97-01af-402f-9536-ddf8a36e130d",
                            "url": "https://api.layer.com/messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/776c6d97-01af-402f-9536-ddf8a36e130d",
                            "mime_type": "image/png",
                            "content": {
                                "id": "layer:///content/7a0aefb8-3c97-11e4-baad-164230d1df67",
                                "size": 172114124
                            },
                            "updated_at": "2017-05-15T18:05:09Z"
                        }
                    ]
                },
                {
                    "operation": "set",
                    "property": "updated_at",
                    "value": "2014-09-15T04:44:59+00:00"
                }
		]
	}
}

Remove message part example:

{
	"type": "change",
	"counter": 7,
	"timestamp": "2014-09-15T04:45:00+00:00",
	"body": {
		"operation": "update",
		"object": {
			"type": "Message",
			"id": "layer:///messages/f3cc7b32-3c92-11e4-baad-164230d1df67",
			"url": "https://api.layer.com/messages/f3cc7b32-3c92-11e4-baad-164230d1df67"
		},
		"data": [{
				    "operation": "remove",
				    "property": "parts",
                    "id": "layer:///messages/dd1894ab-d74d-42e7-8d77-fe134604502f/parts/aedf4b6b-a9d9-40f2-ac86-3e959a3f99a7"
		        },
			    {
				    "operation": "set",
				    "property": "updated_at",
				    "value": "2014-09-15T04:44:59+00:00"
			    }
		]
	}
}

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

Mark a conversation read operation

When a conversation has been marked as read for a user, an operation packet is dispatched. All messages with position less than or equal to position are now considered to be read.

{
  "type": "operation",
  "counter": 13,
  "timestamp": "2014-09-15T04:45:00+00:00",
  "body": {
    "method": "Conversation.mark_all_read",
    "object": {
      "type": "Conversation",
      "id": "layer:///conversations/f3cc7b32-3c92-11e4-baad-164230d1df67",
      "url": "https://api.layer.com/conversations/f3cc7b32-3c92-11e4-baad-164230d1df67"
    },
    "data": [
      {
        "position": 18290719292,
        "identity": BasicIdentity
      }
    ]
  }
}