Photon Engine · AsyncAPI Specification

Photon Realtime Transport Protocol over WebSocket

Version 1.0.0

AsyncAPI 2.6 description of Photon's **WebSocket transport** for the Photon Realtime binary protocol. Photon Realtime (and everything built on it - PUN, Fusion, Quantum, Voice, Chat) is **not** a JSON API. It is a proprietary binary message protocol - operation requests, operation responses, and events, framed inside eNet-style commands (documented at https://doc.photonengine.com/realtime/current/reference/binary-protocol) - that can be carried over three transports: UDP (default, reliable and unreliable channels), TCP, and **WebSocket**. WebSocket is explicitly documented as a first-class transport, not a workaround: clients set `ConnectionProtocol` to `WebSocket` or `WebSocketSecure`, and per https://doc.photonengine.com/realtime/current/connection-and-authentication/secure-networks "Configure your client to use the protocol WebSocketSecure and set the port to 443 for it... Make sure the port is 80 for ws or 443 for wss." Self-hosted Photon Server's WebSocket listener defaults to port 9090 (Master) / 9091 (GameServer secure) per https://doc.photonengine.com/server/v4/operations/websockets-ssl-setup; Photon Cloud uses port 19090 for the equivalent Master listener. WebSocket is the primary transport used by WebGL and other browser-hosted game clients, which cannot open raw UDP/TCP sockets. IMPORTANT HONESTY NOTE: unlike Groq's SSE stream or a typical JSON WebSocket API, the *payload* carried over this WebSocket connection is Photon's own binary wire format, not JSON text frames. This document models the **connection life cycle and message envelope** (operation request / operation response / event, with their code + parameter structure) as officially described in Photon's binary protocol reference; it does not - and cannot - fully reproduce the byte-level encoding here. Treat the `payload` schemas below as a structural description of the binary envelope, not a literal JSON schema of the wire bytes.

View Spec View on GitHub GamingMultiplayerRealtimeNetcodeGame NetworkingWebSocketBinary ProtocolAsyncAPIWebhooksEvents

Channels

/photon/ws
publish sendOperationRequest
Client sends an Operation Request (e.g. Connect, JoinLobby, JoinRoom, CreateRoom, RaiseEvent, SetProperties).
Single duplex WebSocket connection used for the entire Photon session against whichever server role (Name Server, Master Server, or Game Server) the client currently addresses. There is no per-message-type URL path in the real protocol; this channel represents the one long-lived socket carrying every operation request, operation response, and event for the connection's lifetime.

Messages

OperationRequest
Operation Request (binary)
Client-to-server request identified by an operation code.
OperationResponse
Operation Response (binary)
Server-to-client reply to a specific operation code.
EventData
Event (binary)
Server-pushed event identified by an event code.

Servers

wss
nameServer ns.exitgames.com:{port}
Photon Cloud Name Server, reachable over WebSocketSecure. The Name Server returns the region list and hands the client off to a regional Master Server, which in turn hands the client off to a Game Server for actual room gameplay. Self-hosted deployments configure their own WebSocket listener (default port 9090 Master / 9091 GameServer secure); Photon Cloud's equivalent Master listener is port 19090.

AsyncAPI Specification

Raw ↑
asyncapi: '2.6.0'
id: 'urn:com:photonengine:realtime:websocket'
info:
  title: Photon Realtime Transport Protocol over WebSocket
  version: '1.0.0'
  description: |
    AsyncAPI 2.6 description of Photon's **WebSocket transport** for the
    Photon Realtime binary protocol.

    Photon Realtime (and everything built on it - PUN, Fusion, Quantum,
    Voice, Chat) is **not** a JSON API. It is a proprietary binary message
    protocol - operation requests, operation responses, and events, framed
    inside eNet-style commands (documented at
    https://doc.photonengine.com/realtime/current/reference/binary-protocol)
    - that can be carried over three transports: UDP (default, reliable and
    unreliable channels), TCP, and **WebSocket**.

    WebSocket is explicitly documented as a first-class transport, not a
    workaround: clients set `ConnectionProtocol` to `WebSocket` or
    `WebSocketSecure`, and per
    https://doc.photonengine.com/realtime/current/connection-and-authentication/secure-networks
    "Configure your client to use the protocol WebSocketSecure and set the
    port to 443 for it... Make sure the port is 80 for ws or 443 for wss."
    Self-hosted Photon Server's WebSocket listener defaults to port 9090
    (Master) / 9091 (GameServer secure) per
    https://doc.photonengine.com/server/v4/operations/websockets-ssl-setup;
    Photon Cloud uses port 19090 for the equivalent Master listener. WebSocket
    is the primary transport used by WebGL and other browser-hosted game
    clients, which cannot open raw UDP/TCP sockets.

    IMPORTANT HONESTY NOTE: unlike Groq's SSE stream or a typical JSON
    WebSocket API, the *payload* carried over this WebSocket connection is
    Photon's own binary wire format, not JSON text frames. This document
    models the **connection life cycle and message envelope** (operation
    request / operation response / event, with their code + parameter
    structure) as officially described in Photon's binary protocol
    reference; it does not - and cannot - fully reproduce the byte-level
    encoding here. Treat the `payload` schemas below as a structural
    description of the binary envelope, not a literal JSON schema of the
    wire bytes.
  contact:
    name: API Evangelist
    email: kin@apievangelist.com
    url: https://apievangelist.com
  license:
    name: API documentation - Photon Engine Terms of Service
    url: https://www.photonengine.com/en-us/photon/terms-of-service
  x-transport-notes:
    transport: WebSocket (ws:// unsecured, wss:// secured)
    protocol: ws / wss
    direction: bidirectional
    mediaType: application/octet-stream (Photon binary protocol, not JSON text frames)
    alternativeTransports:
      - UDP (default; reliable and unreliable channels)
      - TCP
    connectionSequence: 'Name Server (region list + auth) -> Master Server (matchmaking/lobby) -> Game Server (room gameplay)'
    isJson: false
    source: https://doc.photonengine.com/realtime/current/connection-and-authentication/secure-networks
defaultContentType: application/octet-stream
servers:
  nameServer:
    url: ns.exitgames.com:{port}
    protocol: wss
    protocolVersion: '13'
    description: |
      Photon Cloud Name Server, reachable over WebSocketSecure. The Name
      Server returns the region list and hands the client off to a regional
      Master Server, which in turn hands the client off to a Game Server for
      actual room gameplay. Self-hosted deployments configure their own
      WebSocket listener (default port 9090 Master / 9091 GameServer
      secure); Photon Cloud's equivalent Master listener is port 19090.
    variables:
      port:
        default: '443'
        description: 443 for wss (WebSocketSecure); 80 for plain ws.
        enum:
          - '443'
          - '80'
    bindings:
      ws:
        method: GET
        bindingVersion: '0.1.0'
channels:
  /photon/ws:
    description: |
      Single duplex WebSocket connection used for the entire Photon session
      against whichever server role (Name Server, Master Server, or Game
      Server) the client currently addresses. There is no per-message-type
      URL path in the real protocol; this channel represents the one
      long-lived socket carrying every operation request, operation
      response, and event for the connection's lifetime.
    bindings:
      ws:
        method: GET
        bindingVersion: '0.1.0'
    publish:
      operationId: sendOperationRequest
      summary: Client sends an Operation Request (e.g. Connect, JoinLobby, JoinRoom, CreateRoom, RaiseEvent, SetProperties).
      description: |
        The client sends a binary Operation Request: an 8-byte operation
        header carrying an operation code (uint8) plus a serialized
        hashtable of parameters (parameter code -> value), as described at
        https://doc.photonengine.com/realtime/current/reference/binary-protocol.
        Common operations include Authenticate, JoinLobby, JoinRandomRoom,
        CreateGame, JoinGame, Leave, RaiseEvent, and SetProperties.
      message:
        $ref: '#/components/messages/OperationRequest'
    subscribe:
      operationId: receiveOperationResponseOrEvent
      summary: Server sends an Operation Response or an Event.
      description: |
        The server replies to each Operation Request with an Operation
        Response carrying the same operation code plus a return code and
        optional debug string, and independently pushes Events (for example
        RaiseEvent broadcasts from other actors, or Join/Leave notifications)
        identified by an event code and a data hashtable.
      message:
        oneOf:
          - $ref: '#/components/messages/OperationResponse'
          - $ref: '#/components/messages/EventData'
components:
  messages:
    OperationRequest:
      name: OperationRequest
      title: Operation Request (binary)
      summary: Client-to-server request identified by an operation code.
      contentType: application/octet-stream
      description: |
        Binary envelope: 8-byte operation header (operation code + parameter
        count) followed by a serialized parameter hashtable (parameter code
        -> typed value). Structurally summarized in JSON below for
        readability; the wire format is Photon's own binary serialization,
        not JSON.
      payload:
        $ref: '#/components/schemas/OperationEnvelope'
      examples:
        - name: joinRandomRoom
          summary: Structural summary of a JoinRandomRoom operation request.
          payload:
            operationCode: 226
            operationName: JoinRandomRoom
            parameters:
              expectedMaxPlayers: 4
              matchmakingMode: 0
    OperationResponse:
      name: OperationResponse
      title: Operation Response (binary)
      summary: Server-to-client reply to a specific operation code.
      contentType: application/octet-stream
      description: |
        Binary envelope carrying the same operation code as the triggering
        request, a return code (0 = OK), an optional debug string, and a
        parameter hashtable of result values.
      payload:
        $ref: '#/components/schemas/OperationResponseEnvelope'
      examples:
        - name: joinRandomRoomOk
          summary: Structural summary of a successful JoinRandomRoom response.
          payload:
            operationCode: 226
            operationName: JoinRandomRoom
            returnCode: 0
            debugMessage: null
            parameters:
              roomName: room-af31c
              actorNr: 2
    EventData:
      name: EventData
      title: Event (binary)
      summary: Server-pushed event identified by an event code.
      contentType: application/octet-stream
      description: |
        Binary envelope carrying an event code (uint8) and a parameter/data
        hashtable, pushed by the server without a corresponding client
        request - for example, custom gameplay events raised via
        RaiseEvent, or built-in Join/Leave/PropertiesChanged notifications.
      payload:
        $ref: '#/components/schemas/EventEnvelope'
      examples:
        - name: playerJoinedEvent
          summary: Structural summary of a built-in "actor joined" event.
          payload:
            eventCode: 254
            eventName: Join
            data:
              actorNr: 3
              actorProperties:
                nickName: player3
  schemas:
    OperationEnvelope:
      type: object
      description: Structural summary of a binary Operation Request. Not a literal wire schema.
      required:
        - operationCode
      properties:
        operationCode:
          type: integer
          description: uint8 operation code identifying the requested action.
        operationName:
          type: string
          description: Human-readable operation name (e.g. JoinRandomRoom, RaiseEvent, SetProperties).
        parameters:
          type: object
          additionalProperties: true
          description: Serialized hashtable of parameter code -> typed value.
    OperationResponseEnvelope:
      type: object
      description: Structural summary of a binary Operation Response. Not a literal wire schema.
      required:
        - operationCode
        - returnCode
      properties:
        operationCode:
          type: integer
        operationName:
          type: string
        returnCode:
          type: integer
          description: 0 indicates success; non-zero values are operation-specific error codes.
        debugMessage:
          type: string
          nullable: true
        parameters:
          type: object
          additionalProperties: true
    EventEnvelope:
      type: object
      description: Structural summary of a binary Event. Not a literal wire schema.
      required:
        - eventCode
      properties:
        eventCode:
          type: integer
          description: uint8 event code identifying the event type.
        eventName:
          type: string
          description: Human-readable event name where a built-in code applies (e.g. Join, Leave, PropertiesChanged).
        data:
          type: object
          additionalProperties: true
          description: Serialized hashtable of event data.