JSON Schema
Source: docs/spec/punch-messages.schema.json in the upstream repository.
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://punch.thast.se/spec/punch-messages.schema.json", "title": "Punch WebSocket message envelope", "description": "Machine-readable schema for every message exchanged on the Punch signalling WebSocket. Mirrors src/protocol.ts; the TypeScript and JSON Schema definitions are kept in lock-step.", "$comment": "Version 1.0.0. The schema is normative; src/protocol.ts is the implementation reference.", "oneOf": [ { "$ref": "#/$defs/PeerMessage" }, { "$ref": "#/$defs/ServerMessage" } ], "$defs": { "SessionState": { "type": "string", "enum": ["WAITING", "READY", "CONNECTED", "RELAYING", "CLOSED"] }, "ErrorCode": { "type": "string", "enum": [ "SESSION_FULL", "SESSION_EXPIRED", "STREAM_TAKEN", "AUTH_FAILED", "INVALID_MESSAGE", "SERVER_ERROR" ] }, "SrtState": { "type": "string", "enum": ["connecting", "connected", "disconnected", "error"] }, "TallyState": { "type": "string", "enum": ["off", "preview", "program"] }, "HealthStatus": { "type": "string", "enum": ["healthy", "warning", "critical"] }, "SessionName": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", "description": "Session name; 1-64 characters, alphanumeric plus '.', '_', '-', leading character must be alphanumeric." }, "StreamName": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$", "description": "Stream identifier within a session. Same character class as SessionName." }, "Port": { "type": "integer", "minimum": 1024, "maximum": 65535 }, "PeerMessage": { "description": "Messages sent by a peer to the Punch server.", "oneOf": [ { "$ref": "#/$defs/RegisterMessage" }, { "$ref": "#/$defs/HealthMessage" }, { "$ref": "#/$defs/StatusMessage" }, { "$ref": "#/$defs/TallyMessage" }, { "$ref": "#/$defs/ReadyMessage" } ] }, "RegisterMessage": { "type": "object", "required": ["type", "port"], "additionalProperties": false, "properties": { "type": { "const": "register" }, "stream": { "$ref": "#/$defs/StreamName" }, "port": { "$ref": "#/$defs/Port" }, "role": { "type": "string", "enum": ["sender", "receiver"] }, "meta": { "type": "object", "additionalProperties": true } } }, "HealthMessage": { "type": "object", "required": ["type", "rtt", "retransmit", "bitrate"], "additionalProperties": false, "properties": { "type": { "const": "health" }, "stream": { "$ref": "#/$defs/StreamName" }, "rtt": { "type": "number", "minimum": 0, "description": "Round-trip time in milliseconds." }, "retransmit": { "type": "number", "minimum": 0, "description": "Retransmit ratio (percent). 0 = no retransmits." }, "bitrate": { "type": "number", "minimum": 0, "description": "Current bitrate in bits per second." }, "dropped": { "type": "number", "minimum": 0 }, "buffer": { "type": "number", "minimum": 0 } } }, "StatusMessage": { "type": "object", "required": ["type", "srt"], "additionalProperties": false, "properties": { "type": { "const": "status" }, "stream": { "$ref": "#/$defs/StreamName" }, "srt": { "$ref": "#/$defs/SrtState" } } }, "TallyMessage": { "type": "object", "required": ["type", "state"], "additionalProperties": false, "properties": { "type": { "const": "tally" }, "stream": { "$ref": "#/$defs/StreamName" }, "state": { "$ref": "#/$defs/TallyState" } } }, "ReadyMessage": { "type": "object", "required": ["type"], "additionalProperties": false, "properties": { "type": { "const": "ready" }, "stream": { "$ref": "#/$defs/StreamName" } }, "description": "Peer signals it has read the connection string and will start SRT." }, "ServerMessage": { "description": "Messages sent by the Punch server to a peer.", "oneOf": [ { "$ref": "#/$defs/PeerInfoMessage" }, { "$ref": "#/$defs/PeerMatchMessage" }, { "$ref": "#/$defs/SessionUpdateMessage" }, { "$ref": "#/$defs/TallyBroadcast" }, { "$ref": "#/$defs/HealthReportMessage" }, { "$ref": "#/$defs/ErrorMessage" }, { "$ref": "#/$defs/SessionClosedMessage" }, { "$ref": "#/$defs/StartMessage" } ] }, "PeerInfoMessage": { "type": "object", "required": ["type", "ip", "port", "localPort", "passphrase", "latency"], "additionalProperties": false, "properties": { "type": { "const": "peer" }, "stream": { "$ref": "#/$defs/StreamName" }, "ip": { "type": "string", "description": "Remote peer's reported public IP." }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "localPort": { "$ref": "#/$defs/Port" }, "passphrase": { "type": "string", "minLength": 10, "description": "Pre-shared passphrase for SRT AES." }, "latency": { "type": "integer", "minimum": 20, "maximum": 8000, "description": "Suggested SRT latency in milliseconds." }, "meta": { "type": "object", "additionalProperties": true } } }, "PeerMatchMessage": { "type": "object", "required": ["type", "stream", "peer_a", "peer_b", "localPort", "passphrase", "latency"], "additionalProperties": false, "properties": { "type": { "const": "peer_match" }, "stream": { "$ref": "#/$defs/StreamName" }, "peer_a": { "$ref": "#/$defs/PeerEndpoint" }, "peer_b": { "$ref": "#/$defs/PeerEndpoint" }, "localPort": { "$ref": "#/$defs/Port" }, "passphrase": { "type": "string", "minLength": 10 }, "latency": { "type": "integer", "minimum": 20, "maximum": 8000 } }, "description": "Sent only to admin observers when a stream's peers are matched." }, "PeerEndpoint": { "type": "object", "required": ["ip", "port"], "additionalProperties": false, "properties": { "ip": { "type": "string" }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 } } }, "StreamStatus": { "type": "object", "required": ["state", "peers"], "additionalProperties": false, "properties": { "state": { "type": "string" }, "peers": { "type": "integer", "minimum": 0 } } }, "SessionUpdateMessage": { "type": "object", "required": ["type", "state", "streams", "connected", "total"], "additionalProperties": false, "properties": { "type": { "const": "session" }, "state": { "$ref": "#/$defs/SessionState" }, "streams": { "type": "object", "additionalProperties": { "$ref": "#/$defs/StreamStatus" } }, "connected": { "type": "integer", "minimum": 0 }, "total": { "type": "integer", "minimum": 0 } } }, "TallyBroadcast": { "type": "object", "required": ["type", "stream", "state"], "additionalProperties": false, "properties": { "type": { "const": "tally" }, "stream": { "$ref": "#/$defs/StreamName" }, "state": { "$ref": "#/$defs/TallyState" } } }, "HealthStreamReport": { "type": "object", "required": ["rtt", "retransmit", "bitrate", "status"], "additionalProperties": false, "properties": { "rtt": { "type": "number", "minimum": 0 }, "retransmit": { "type": "number", "minimum": 0 }, "bitrate": { "type": "number", "minimum": 0 }, "status": { "$ref": "#/$defs/HealthStatus" } } }, "HealthReportMessage": { "type": "object", "required": ["type", "streams"], "additionalProperties": false, "properties": { "type": { "const": "health_report" }, "streams": { "type": "object", "additionalProperties": { "$ref": "#/$defs/HealthStreamReport" } } } }, "ErrorMessage": { "type": "object", "required": ["type", "code", "message"], "additionalProperties": false, "properties": { "type": { "const": "error" }, "code": { "$ref": "#/$defs/ErrorCode" }, "message": { "type": "string" } } }, "SessionClosedMessage": { "type": "object", "required": ["type", "reason"], "additionalProperties": false, "properties": { "type": { "const": "session_closed" }, "reason": { "type": "string", "enum": ["admin_closed", "ttl_expired", "error"] } } }, "StartMessage": { "type": "object", "required": ["type", "stream"], "additionalProperties": false, "properties": { "type": { "const": "start" }, "stream": { "$ref": "#/$defs/StreamName" } }, "description": "Coordinated 'go' signal — sent to all stream peers when both sides have signalled ready." } }}