Synchronization

The /sync endpoint is the primary mechanism for clients to receive new events and maintain client state.

GET /sync

GET /_matrix/client/v3/sync?filter=...&since=...&timeout=30000&full_state=true

Parameters

ParameterTypeDescription
filterJSONFilter object (or filter ID)
sincestringStream token for incremental sync
timeoutintLong-poll timeout in ms (max 30s)
full_stateboolInclude all state events regardless of since

Response Structure

{
  "next_batch": "s72595_0_0",
  "rooms": {
    "join": {
      "!room:localhost": {
        "timeline": { "events": [...], "limited": false },
        "state": { "events": [...] },
        "ephemeral": { "events": [...] },
        "account_data": { "events": [...] }
      }
    },
    "invite": {},
    "leave": {}
  },
  "presence": { "events": [...] },
  "device_lists": { "changed": [...], "left": [...] },
  "device_one_time_keys_count": { "signed_curve25519": 50 }
}

Stream Tokens

Stream tokens are opaque strings that encode a position in the event stream. They are used for:

  • Incremental sync: since parameter resumes from a previous position
  • Pagination: /messages and /context use from/to tokens
  • Gap detection: timeline.limited = true indicates events were lost (client should re-sync)

Tokens are base64-encoded tuples of (room_id, stream_ordering).

Long-Polling

When timeout > 0, the server holds the connection open until:

  • New events arrive for the user
  • The timeout expires
  • A keep-alive is needed

This reduces client polling frequency and latency.

Filters

Filters control which events appear in /sync:

{
  "room": {
    "rooms": ["!room:localhost"],
    "state": { "types": ["m.room.member"] },
    "timeline": { "limit": 50 },
    "ephemeral": { "types": ["m.typing", "m.receipt"] }
  },
  "presence": { "types": ["m.presence"] }
}

Filters can be saved via POST /filter and referenced by ID.

Ephemeral Events

Ephemeral events are not persisted long-term but are included in /sync:

EventDescription
m.typingUsers currently typing
m.receiptRead receipts
m.read_markersRead marker positions
m.presenceUser online/offline status

Account Data

Account data events are user-specific and included in every sync response:

EventDescription
m.push_rulesPush notification rules (injected dynamically)
m.ignored_user_listIgnored users (injected dynamically)
m.directDirect message room mapping

Device Lists

When a user joins, leaves, or is banned from a room, the device list change notification system triggers device_lists.changed / device_lists.left entries in the sync response. This allows E2EE clients to track which devices to encrypt for.