Connection & Lifecycle

Endpoints

EndpointDescription
ws://host:8443/v1/wsPrimary WebSocket endpoint
ws://host:8443/Alias for /v1/ws

Optional query parameter: ?resume_from=<seq> to resume the stream (see Reliability).

Connection Lifecycle

Client                                         Server
  │                                               │
  │  WebSocket upgrade (?resume_from=N)           │
  ├──────────────────────────────────────────────►│
  │                                               │
  │  [replay if resume_from is valid]             │
  │◄──────────────────────────────────────────────┤  frames 1..N
  │                                               │
  │  Subscribe {"subscribe": [...]}               │
  ├──────────────────────────────────────────────►│  required
  │                                               │
  │  Hello {protocol_version, limits, ...}        │
  │◄──────────────────────────────────────────────┤  before first Subscribe response
  │                                               │
  │  [current state snapshot]                     │
  │◄──────────────────────────────────────────────┤  TPS, contention, lifecycle
  │                                               │
  │  [live events]                                │
  │◄──────────────────────────────────────────────┤  continuous stream
  │                                               │
  │  Subscribe {"subscribe": [...]}               │
  ├──────────────────────────────────────────────►│  update (unlimited)
  │                                               │
  │  Ping (client-initiated)                      │
  ├──────────────────────────────────────────────►│  keeps connection alive
  │  Pong                                         │
  │◄──────────────────────────────────────────────┤
  │                                               │
  │  Close                                        │
  ├──────────────────────────────────────────────►│

Key points:

  • Hello is sent before the first Subscribe response, not immediately upon connection
  • No events are sent until a Subscribe message is received
  • Each new Subscribe fully replaces the previous subscription

Hello Frame

{
  "seq": 0,
  "Hello": {
    "protocol_version": 1,
    "server_version": "0.2.0",
    "chain_id": 10143,
    "block_number": 59400000,
    "available_filters": ["txn_index", "log_index", "address", "topics", "sender", "to", "function_selector"],
    "blocked_events": ["AccountAccess", "StorageAccess", "RecordError", "EvmError"],
    "limits": {
      "backfill_events": 100000,
      "buffer_per_client": 4096,
      "slow_off_limit": 10000,
      "heartbeat_interval": 30,
      "heartbeat_timeout": 60,
      "max_subscribes": 3
    }
  }
}
FieldTypeDescription
protocol_versionu32Protocol version (current: 1). The server logs a warning if the client sends a different version, but continues operating (forward-compatible).
server_versionstringServer version (semver)
chain_idu64Network ID (e.g. 10143 = Monad Devnet)
block_numberu64Latest block number seen by the server at the time of Hello
available_filtersstring[]Supported field filter names for advanced subscriptions
blocked_eventsstring[]Event types suppressed by the server's blacklist. These events will not be delivered regardless of your subscription.
limits.backfill_eventsusizeNumber of entries in the resume ring buffer (default: 100,000). This is how many past messages the server can replay on reconnect. See Reliability.
limits.buffer_per_clientusizePer-client outbound send queue capacity (default: 4,096 messages). When full, new messages are dropped. See Reliability — Backpressure.
limits.slow_off_limitu64Maximum cumulative message drops before the server disconnects the client (default: 10,000).
limits.heartbeat_intervalu64How often the server checks for client activity (seconds).
limits.heartbeat_timeoutu64Maximum seconds without any client activity before disconnect.
limits.max_subscribesusizeMaximum number of items (event types + metrics) allowed in a single subscribe message. 0 = unlimited.

Note: The Hello frame uses seq: 0. This is a control message; clients must not update their resume cursor from seq: 0 frames. Only track seq > 0 for ?resume_from=.

Heartbeat & Liveness

Unlike typical WebSocket servers, the Monad Events Stream does not send Ping frames. Instead, it uses a timeout-based liveness model:

  1. Every heartbeat_interval seconds (default: 30s), the server checks when the last client activity was received
  2. If more than heartbeat_timeout seconds (default: 60s) have elapsed without any activity from the client, the connection is closed
  3. "Activity" includes: any text message, Ping frame, Pong frame

What this means for clients:

  • Your WebSocket client must send periodic Ping frames or messages to stay alive
  • Most WebSocket libraries handle Ping/Pong automatically at the transport layer
  • If you're using a raw WebSocket implementation, send a Ping every ~25 seconds
  • Subscribing to high-frequency events (e.g., BlockStart) already generates enough server-to-client traffic, but the server only tracks client-to-server activity