NEXIS
Api reference

Protocol

Envelope, handshake, channels, RPC, and state sync format.

Protocol

Envelope

{
  "v": 1,
  "t": "message.type",
  "rid": "optional-request-id",
  "room": "optional-room-id",
  "p": {}
}
  • v: protocol version (1)
  • t: message type (required)
  • rid: request/response correlation id (optional)
  • room: room id (optional)
  • p: payload (optional)

Handshake

Client first message is always JSON handshake:

{
  "v": 1,
  "codecs": ["msgpack", "json"],
  "project_id": "demo-project",
  "token": "...",
  "session_id": "optional"
}

Server does:

  1. protocol version validation
  2. auth check (based on auth mode)
  3. codec negotiation (msgpack preferred if both support)
  4. handshake.ok response

Handshake flow

Channels

Logical channels over WebSocket:

  • reliable (default)
  • unreliable (drop-allowed under pressure)

State Sync Messages

  • state.snapshot full state with seq and checksum
  • state.patch incremental ops (set/del)
  • state.ack client ack
  • state.resync client asks fresh snapshot

Patch payload:

{
  "seq": 43,
  "ops": [
    { "op": "set", "path": "/counter", "value": 4 },
    { "op": "del", "path": "/foo" }
  ]
}

Room message payload contract

When sending custom room messages (t = "room.message"), payload shape is:

{
  "type": "player.move",
  "data": { "x": 10, "y": 4, "seq": 18 }
}

Binary variant (t = "room.message.bytes") uses:

{
  "type": "voice.chunk",
  "data_b64": "..."
}

Common call types

  • room: room.join_or_create, room.leave, room.list, room.message
  • matchmaking: matchmaking.enqueue, matchmaking.dequeue
  • state: state.snapshot, state.patch, state.ack, state.resync
  • rpc: rpc.request, rpc.response

Unknown rid is rejected by RPC tracker.

Typed Envelope Validation

const : unknown = { : 1, : 'state.patch', : { : 10, : [] } };
if (()) {
  .(.);
}

On this page