{"openapi":"3.1.0","info":{"title":"HeteroCloud Flow Public API","description":"Public room, matchmaking, participant connection, and TURN credential API. Obtain the three short-lived X-Flow-* header values from HeteroCloud and send all three on every REST request. P2P join responses identify flow-signaling.v1, link the complete AsyncAPI WebSocket frame contract, and return STUN plus authenticated TURN as a direct-first ICE server list. Clients use normal WebRTC candidate selection; TURN is selected automatically only when direct connectivity checks fail. Relay-only selection is not part of the Flow API. Every request is subject to a system source-IP ceiling; authenticated requests also share the Flow service's console-configured source-IP token bucket across all API replicas. Ready rooms are removed after ten minutes without P2P or SFU participants.","license":{"name":"MIT","identifier":"MIT"},"version":"0.1.20"},"servers":[{"url":"https://flow.heterocloud.mizuame.app"}],"paths":{"/v1/queues/{queue_name}/tickets":{"get":{"tags":["Matchmaking"],"summary":"List matchmaking tickets in one queue and service scope.","operationId":"list_tickets","parameters":[{"name":"queue_name","in":"path","description":"Queue name","required":true,"schema":{"type":"string","maxLength":96}},{"name":"limit","in":"query","description":"Maximum items; defaults to 50","required":false,"schema":{"type":"integer","format":"int64","maximum":200,"minimum":1}}],"responses":{"200":{"description":"Scoped ticket list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketListResponse"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.queue.read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]},"post":{"tags":["Matchmaking"],"summary":"Create a matchmaking ticket in a named queue.","operationId":"create_ticket","parameters":[{"name":"queue_name","in":"path","description":"Queue name","required":true,"schema":{"type":"string","maxLength":96}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTicketRequest"}}},"required":true},"responses":{"201":{"description":"Ticket created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchmakingTicket"}}}},"400":{"description":"Ticket request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.queue.write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/rooms":{"get":{"tags":["Rooms"],"summary":"List rooms in the signed service scope.","operationId":"list_rooms","parameters":[{"name":"limit","in":"query","description":"Maximum items; defaults to 50","required":false,"schema":{"type":"integer","format":"int64","maximum":200,"minimum":1}}],"responses":{"200":{"description":"Scoped room list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomListResponse"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.room.read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]},"post":{"tags":["Rooms"],"summary":"Create a P2P or SFU room.","operationId":"create_room","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoomRequest"}}},"required":true},"responses":{"201":{"description":"Ready room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRoom"}}}},"400":{"description":"Room request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.room.create","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Service or principal concurrent room limit was reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"SFU provider is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/rooms/{room_id}":{"get":{"tags":["Rooms"],"summary":"Read one room in the signed service scope.","operationId":"get_room","parameters":[{"name":"room_id","in":"path","description":"Room ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRoom"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.room.read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Room was not found in this service scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/rooms/{room_id}/join":{"post":{"tags":["Connectivity"],"summary":"Issue mode-specific short-lived connection data for a room.","description":"The returned ICE server list is fixed to normal WebRTC candidate selection:\nclients try host and STUN-derived candidates and use TURN when direct\nconnectivity checks fail. Flow does not expose a relay-only mode.","operationId":"join_room","parameters":[{"name":"room_id","in":"path","description":"Room ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinRoomRequest"}}},"required":true},"responses":{"200":{"description":"P2P signaling or SFU connection data with direct-first ICE servers and automatic TURN fallback","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinRoomResponse"}}}},"400":{"description":"Join request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Signed access context is missing, invalid, or nearly expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.room.join","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Room was not found in this service scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Room is not ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"Connection provider is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/service-overview":{"get":{"tags":["Overview"],"summary":"Read current service capacity, usage, and connection endpoints.","operationId":"service_overview","responses":{"200":{"description":"Current Flow service overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOverviewResponse"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.metrics.read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP token bucket is empty","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0},"description":"Seconds before retrying"},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0},"description":"Configured burst capacity"},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0},"description":"Tokens remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0},"description":"Seconds until the bucket is full"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/tickets/{ticket_id}":{"get":{"tags":["Matchmaking"],"summary":"Read a matchmaking ticket and its assignment.","operationId":"get_ticket","parameters":[{"name":"ticket_id","in":"path","description":"Ticket ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ticket and optional assignment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.queue.read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Ticket was not found in this service scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]},"delete":{"tags":["Matchmaking"],"summary":"Cancel the caller's queued matchmaking ticket.","operationId":"cancel_ticket","parameters":[{"name":"ticket_id","in":"path","description":"Ticket ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Cancelled ticket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchmakingTicket"}}}},"401":{"description":"Signed access context is missing or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.queue.write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Ticket was not found in this service scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Ticket can no longer be cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}},"/v1/turn-credentials":{"post":{"tags":["Connectivity"],"summary":"Issue short-lived TURN REST credentials for the signed principal.","description":"Credentials make relay candidates available to normal ICE negotiation;\nissuing them does not select or force relay-only transport.","operationId":"issue_turn_credentials","responses":{"200":{"description":"Optional TURN fallback URLs and short-lived credentials; this response does not force relay transport","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TurnCredentials"}}}},"400":{"description":"Credential request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Signed access context is missing, invalid, or nearly expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The context lacks flow.turn.issue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Source IP request limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","format":"int64","minimum":0}},"X-RateLimit-Limit":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Remaining":{"schema":{"type":"integer","format":"int32","minimum":0}},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Request admission backend is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"flow_principal":[],"flow_signature":[],"flow_timestamp":[]}]}}},"components":{"schemas":{"CreateRoomRequest":{"type":"object","required":["mode"],"properties":{"max_participants":{"type":"integer","format":"int32","default":16,"maximum":1000,"minimum":2},"metadata":{},"mode":{"$ref":"#/components/schemas/SessionMode"},"name":{"type":["string","null"],"maxLength":160}}},"CreateTicketRequest":{"type":"object","required":["mode","match_size"],"properties":{"attributes":{},"match_size":{"type":"integer","format":"int32","maximum":100,"minimum":2},"mode":{"$ref":"#/components/schemas/SessionMode"},"ttl_seconds":{"type":["integer","null"],"format":"int32"}}},"ErrorBody":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}},"ErrorEnvelope":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}}},"FlowRoom":{"type":"object","required":["id","organization_id","project_id","service_instance_id","created_by_principal_id","name","mode","state","max_participants","metadata","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"created_by_principal_id":{"type":"string","format":"uuid"},"failure_reason":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"max_participants":{"type":"integer","format":"int32"},"metadata":{},"mode":{"$ref":"#/components/schemas/SessionMode"},"name":{"type":"string"},"organization_id":{"type":"string","format":"uuid"},"project_id":{"type":"string","format":"uuid"},"provider_room_name":{"type":["string","null"]},"service_instance_id":{"type":"string","format":"uuid"},"state":{"$ref":"#/components/schemas/RoomState"},"updated_at":{"type":"string","format":"date-time"}}},"IceConfiguration":{"type":"object","description":"WebRTC `RTCIceServer` values for direct ICE with TURN fallback.","required":["ice_servers","expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"Expiration of the TURN credentials contained in the server list."},"ice_servers":{"type":"array","items":{"$ref":"#/components/schemas/IceServer"},"description":"Pass this array to `RTCPeerConnection` as `iceServers` without setting\n`iceTransportPolicy` to `relay`."}}},"IceServer":{"type":"object","description":"One browser-compatible `RTCIceServer` entry.","required":["urls"],"properties":{"credential":{"type":["string","null"]},"urls":{"type":"array","items":{"type":"string"}},"username":{"type":["string","null"]}}},"JoinRoomRequest":{"type":"object","properties":{"can_publish":{"type":"boolean"},"can_subscribe":{"type":"boolean"},"display_name":{"type":["string","null"],"maxLength":128}}},"JoinRoomResponse":{"type":"object","required":["room_id","mode","connection"],"properties":{"connection":{"$ref":"#/components/schemas/RoomConnection"},"mode":{"$ref":"#/components/schemas/SessionMode"},"room_id":{"type":"string","format":"uuid"}}},"MatchAssignment":{"type":"object","required":["id","ticket_id","room_id","peer_principal_ids","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"peer_principal_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"room_id":{"type":"string","format":"uuid"},"ticket_id":{"type":"string","format":"uuid"}}},"MatchmakingTicket":{"type":"object","required":["id","organization_id","project_id","service_instance_id","principal_id","queue_name","mode","match_size","state","attributes","created_at","updated_at","expires_at"],"properties":{"attributes":{},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"match_size":{"type":"integer","format":"int32"},"mode":{"$ref":"#/components/schemas/SessionMode"},"organization_id":{"type":"string","format":"uuid"},"principal_id":{"type":"string","format":"uuid"},"project_id":{"type":"string","format":"uuid"},"queue_name":{"type":"string"},"reservation_id":{"type":["string","null"],"format":"uuid"},"service_instance_id":{"type":"string","format":"uuid"},"state":{"$ref":"#/components/schemas/TicketState"},"updated_at":{"type":"string","format":"date-time"}}},"RoomConnection":{"oneOf":[{"type":"object","required":["protocol","asyncapi_urls","urls","ice","type"],"properties":{"asyncapi_urls":{"type":"array","items":{"type":"string"}},"ice":{"$ref":"#/components/schemas/IceConfiguration"},"protocol":{"type":"string"},"type":{"type":"string","enum":["p2p"]},"urls":{"type":"array","items":{"type":"string"}}}},{"type":"object","required":["urls","token","ice","type"],"properties":{"ice":{"$ref":"#/components/schemas/IceConfiguration"},"token":{"type":"string"},"type":{"type":"string","enum":["sfu"]},"urls":{"type":"array","items":{"type":"string"}}}}]},"RoomListResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FlowRoom"}}}},"RoomState":{"type":"string","enum":["provisioning","ready","failed","closed"]},"ServiceEndpoints":{"type":"object","required":["api","signaling","livekit","stun","turn"],"properties":{"api":{"type":"array","items":{"type":"string"}},"livekit":{"type":"array","items":{"type":"string"}},"signaling":{"type":"array","items":{"type":"string"}},"stun":{"type":"array","items":{"type":"string"}},"turn":{"type":"array","items":{"type":"string"}}}},"ServiceOverviewResponse":{"type":"object","required":["measured_at","active_rooms","concurrent_connections","sfu_participants","p2p_connections","ingress_bytes","egress_bytes","transferred_bytes","endpoints","principal_room_limit","room_idle_timeout_seconds"],"properties":{"active_rooms":{"type":"integer","format":"int64","minimum":0},"concurrent_connections":{"type":"integer","format":"int64","minimum":0},"egress_bytes":{"type":"integer","format":"int64"},"endpoints":{"$ref":"#/components/schemas/ServiceEndpoints"},"ingress_bytes":{"type":"integer","format":"int64"},"measured_at":{"type":"string","format":"date-time"},"p2p_connections":{"type":"integer","format":"int64","minimum":0},"principal_room_limit":{"type":"integer","format":"int64","minimum":0},"room_idle_timeout_seconds":{"type":"integer","format":"int64","minimum":0},"room_limit":{"type":["integer","null"],"format":"int64","minimum":0},"sfu_participants":{"type":"integer","format":"int64","minimum":0},"transferred_bytes":{"type":"integer","format":"int64"},"turn_allocations":{"type":["integer","null"],"format":"int64","minimum":0}}},"SessionMode":{"type":"string","enum":["p2p","sfu"]},"SignalingAuthenticationFrame":{"oneOf":[{"type":"object","required":["principal_context","timestamp","signature","type"],"properties":{"principal_context":{"type":"string"},"signature":{"type":"string"},"timestamp":{"type":"string"},"type":{"type":"string","enum":["signed_context"]}}}]},"SignalingClientSignal":{"type":"object","required":["type","target","payload"],"properties":{"payload":{},"target":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/SignalingSignalKind"}},"additionalProperties":false},"SignalingPeer":{"type":"object","required":["connection_id","principal_id"],"properties":{"connection_id":{"type":"string","format":"uuid"},"principal_id":{"type":"string","format":"uuid"}}},"SignalingServerFrame":{"oneOf":[{"type":"object","required":["connection_id","room_id","principal_id","peers","type"],"properties":{"connection_id":{"type":"string","format":"uuid"},"peers":{"type":"array","items":{"$ref":"#/components/schemas/SignalingPeer"}},"principal_id":{"type":"string","format":"uuid"},"room_id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["authenticated"]}}},{"type":"object","required":["peer","type"],"properties":{"peer":{"$ref":"#/components/schemas/SignalingPeer"},"type":{"type":"string","enum":["peer_joined"]}}},{"type":"object","required":["peer","type"],"properties":{"peer":{"$ref":"#/components/schemas/SignalingPeer"},"type":{"type":"string","enum":["peer_left"]}}},{"type":"object","required":["kind","sender","payload","sent_at","type"],"properties":{"kind":{"$ref":"#/components/schemas/SignalingSignalKind"},"payload":{},"sender":{"type":"string","format":"uuid"},"sent_at":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["signal"]}}},{"type":"object","required":["code","message","type"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"type":{"type":"string","enum":["error"]}}}]},"SignalingSignalKind":{"type":"string","enum":["offer","answer","ice_candidate","renegotiate","leave"]},"TicketListResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/MatchmakingTicket"}}}},"TicketResponse":{"type":"object","required":["ticket"],"properties":{"assignment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MatchAssignment"}]},"ticket":{"$ref":"#/components/schemas/MatchmakingTicket"}}},"TicketState":{"type":"string","enum":["queued","matching","assigned","cancelled","expired"]},"TurnCredentials":{"type":"object","required":["urls","username","password","expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time"},"password":{"type":"string"},"urls":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}}},"securitySchemes":{"flow_principal":{"type":"apiKey","in":"header","name":"X-Flow-Principal","description":"Base64url-encoded signed principal context returned by HeteroCloud"},"flow_signature":{"type":"apiKey","in":"header","name":"X-Flow-Signature","description":"HMAC signature returned with the signed principal context"},"flow_timestamp":{"type":"apiKey","in":"header","name":"X-Flow-Timestamp","description":"Issued-at timestamp returned with the signed principal context"}}},"tags":[{"name":"Overview","description":"Service capacity and endpoint discovery"},{"name":"Matchmaking","description":"Queue and ticket operations"},{"name":"Rooms","description":"P2P and SFU room lifecycle"},{"name":"Connectivity","description":"Direct-first ICE, signaling, participant, and TURN fallback data"}],"externalDocs":{"url":"https://flow.heterocloud.mizuame.app/asyncapi.json","description":"Complete flow-signaling.v1 WebSocket authentication, presence, SDP, and ICE frame contract"},"x-flow-signaling-protocol":"flow-signaling.v1","x-flow-signaling-asyncapi":["https://flow.heterocloud.mizuame.app/asyncapi.json"]}