{"asyncapi":"2.6.0","info":{"title":"IceLive Socket API","version":"0.1.0","description":"Connect to the `/socket` namespace with a Socket.IO client, passing the access token in the connection `auth` payload: `{ \"token\": \"<JWT>\" }`. On success the server emits `authenticated`; an invalid token rejects the connection. Every connected user is auto-joined to a personal room (`user_{id}`) and, after `join_live`, to the live room (`live_{id}`)."},"servers":{"local":{"url":"localhost:8000","protocol":"socketio","description":"Socket.IO server, namespace /socket"}},"channels":{"/socket":{"description":"Live streaming, presence and moderation.","publish":{"description":"Events the client sends to the server.","message":{"oneOf":[{"$ref":"#/components/messages/accept_live_invite"},{"$ref":"#/components/messages/accept_live_join_request"},{"$ref":"#/components/messages/call_accept"},{"$ref":"#/components/messages/call_cancel"},{"$ref":"#/components/messages/call_end"},{"$ref":"#/components/messages/call_initiate"},{"$ref":"#/components/messages/call_reject"},{"$ref":"#/components/messages/decline_live_invite"},{"$ref":"#/components/messages/delete_message"},{"$ref":"#/components/messages/host_left"},{"$ref":"#/components/messages/invite_to_live"},{"$ref":"#/components/messages/join_live"},{"$ref":"#/components/messages/kick_user"},{"$ref":"#/components/messages/leave_live"},{"$ref":"#/components/messages/live_room_end"},{"$ref":"#/components/messages/mark_read"},{"$ref":"#/components/messages/reject_live_join_request"},{"$ref":"#/components/messages/request_join_live"},{"$ref":"#/components/messages/send_message"},{"$ref":"#/components/messages/set_active_host"},{"$ref":"#/components/messages/typing"},{"$ref":"#/components/messages/update_media_state"}]}},"subscribe":{"description":"Events the client receives from the server.","message":{"oneOf":[{"$ref":"#/components/messages/accepted_live_join_request"},{"$ref":"#/components/messages/active_host_set"},{"$ref":"#/components/messages/authenticated"},{"$ref":"#/components/messages/call_accepted"},{"$ref":"#/components/messages/call_cancelled"},{"$ref":"#/components/messages/call_connected"},{"$ref":"#/components/messages/call_ended"},{"$ref":"#/components/messages/call_rejected"},{"$ref":"#/components/messages/call_ringing"},{"$ref":"#/components/messages/error"},{"$ref":"#/components/messages/gift_received"},{"$ref":"#/components/messages/host_left_live"},{"$ref":"#/components/messages/incoming_call"},{"$ref":"#/components/messages/join_live_request_sent"},{"$ref":"#/components/messages/joined_live"},{"$ref":"#/components/messages/kicked_successfully"},{"$ref":"#/components/messages/live_ended"},{"$ref":"#/components/messages/live_invite_accepted"},{"$ref":"#/components/messages/live_invite_declined"},{"$ref":"#/components/messages/live_invite_received"},{"$ref":"#/components/messages/live_invite_sent"},{"$ref":"#/components/messages/live_join_request_received"},{"$ref":"#/components/messages/live_started"},{"$ref":"#/components/messages/media_state_changed"},{"$ref":"#/components/messages/message_deleted"},{"$ref":"#/components/messages/message_read"},{"$ref":"#/components/messages/message_sent"},{"$ref":"#/components/messages/new_message"},{"$ref":"#/components/messages/rejected_live_join_request"},{"$ref":"#/components/messages/request_join_live_accepted"},{"$ref":"#/components/messages/request_join_live_rejected"},{"$ref":"#/components/messages/role_changed"},{"$ref":"#/components/messages/user_joined_live"},{"$ref":"#/components/messages/user_left_live"},{"$ref":"#/components/messages/user_offline"},{"$ref":"#/components/messages/user_online"},{"$ref":"#/components/messages/user_typing"},{"$ref":"#/components/messages/you_kicked"}]}}}},"components":{"messages":{"accept_live_invite":{"name":"accept_live_invite","title":"accept_live_invite","summary":"Invitee accepts their pending invite; they may then join directly.","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"accept_live_join_request":{"name":"accept_live_join_request","title":"accept_live_join_request","summary":"Active host approves a pending request; the requester may then join.","payload":{"description":"An action targeting another user in the room (host moderation, or a\nmember inviting someone into a private room).","properties":{"live_id":{"title":"Live Id","type":"integer"},"user_id":{"title":"User Id","type":"integer"}},"required":["live_id","user_id"],"title":"LiveUserActionPayload","type":"object"}},"call_accept":{"name":"call_accept","title":"call_accept","summary":"Answer a ringing call. Acks the callee with their token; the caller gets ``call_accepted``.","payload":{"properties":{"call_id":{"title":"Call Id","type":"integer"}},"required":["call_id"],"title":"CallActionPayload","type":"object"}},"call_cancel":{"name":"call_cancel","title":"call_cancel","summary":"Caller hangs up before it connects; the callee gets ``call_cancelled``.","payload":{"properties":{"call_id":{"title":"Call Id","type":"integer"}},"required":["call_id"],"title":"CallActionPayload","type":"object"}},"call_end":{"name":"call_end","title":"call_end","summary":"Either party ends the call; the other party gets ``call_ended``.","payload":{"properties":{"call_id":{"title":"Call Id","type":"integer"}},"required":["call_id"],"title":"CallActionPayload","type":"object"}},"call_initiate":{"name":"call_initiate","title":"call_initiate","summary":"Ring a user. Acks the caller with their token; the callee gets ``incoming_call``.","payload":{"$defs":{"CallType":{"enum":["audio","video"],"title":"CallType","type":"string"}},"properties":{"callee_id":{"title":"Callee Id","type":"integer"},"call_type":{"$ref":"#/$defs/CallType","default":"audio"}},"required":["callee_id"],"title":"CallInitiatePayload","type":"object"}},"call_reject":{"name":"call_reject","title":"call_reject","summary":"Decline a ringing call; the caller gets ``call_rejected``.","payload":{"properties":{"call_id":{"title":"Call Id","type":"integer"}},"required":["call_id"],"title":"CallActionPayload","type":"object"}},"decline_live_invite":{"name":"decline_live_invite","title":"decline_live_invite","summary":"Invitee declines their pending invite.","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"delete_message":{"name":"delete_message","title":"delete_message","summary":"Delete the caller's own message; the thread gets ``message_deleted``.","payload":{"properties":{"message_id":{"title":"Message Id","type":"integer"}},"required":["message_id"],"title":"DeleteMessagePayload","type":"object"}},"host_left":{"name":"host_left","title":"host_left","summary":"Client leaves (or host steps out). The room learns whether the host left so the client can react (e.g. show 'host will be right back').","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"invite_to_live":{"name":"invite_to_live","title":"invite_to_live","summary":"A member invites another user into a private room. Acks the inviter and notifies the invitee in real time.","payload":{"description":"An action targeting another user in the room (host moderation, or a\nmember inviting someone into a private room).","properties":{"live_id":{"title":"Live Id","type":"integer"},"user_id":{"title":"User Id","type":"integer"}},"required":["live_id","user_id"],"title":"LiveUserActionPayload","type":"object"}},"join_live":{"name":"join_live","title":"join_live","summary":"Client joins a room; gets a private ack with a scoped LiveKit token, and everyone already in the room is told a new participant arrived.","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"kick_user":{"name":"kick_user","title":"kick_user","summary":"Active host removes a participant and blocks their rejoin.","payload":{"description":"An action targeting another user in the room (host moderation, or a\nmember inviting someone into a private room).","properties":{"live_id":{"title":"Live Id","type":"integer"},"user_id":{"title":"User Id","type":"integer"}},"required":["live_id","user_id"],"title":"LiveUserActionPayload","type":"object"}},"leave_live":{"name":"leave_live","title":"leave_live","summary":"Client leaves (or host steps out). The room learns whether the host left so the client can react (e.g. show 'host will be right back').","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"live_room_end":{"name":"live_room_end","title":"live_room_end","summary":"Active host ends the room for everyone.","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"mark_read":{"name":"mark_read","title":"mark_read","summary":"Mark a conversation read; the other members get ``message_read``.","payload":{"properties":{"conversation_id":{"title":"Conversation Id","type":"integer"}},"required":["conversation_id"],"title":"ConversationActionPayload","type":"object"}},"reject_live_join_request":{"name":"reject_live_join_request","title":"reject_live_join_request","summary":"Active host rejects a pending request.","payload":{"description":"An action targeting another user in the room (host moderation, or a\nmember inviting someone into a private room).","properties":{"live_id":{"title":"Live Id","type":"integer"},"user_id":{"title":"User Id","type":"integer"}},"required":["live_id","user_id"],"title":"LiveUserActionPayload","type":"object"}},"request_join_live":{"name":"request_join_live","title":"request_join_live","summary":"Viewer asks to join a public room. Acks the requester and notifies the active host.","payload":{"properties":{"live_id":{"title":"Live Id","type":"integer"}},"required":["live_id"],"title":"LiveRoomPayload","type":"object"}},"send_message":{"name":"send_message","title":"send_message","summary":"Send a DM to a conversation or straight to a user; the sender gets a ``message_sent`` ack and every other member gets ``new_message``.","payload":{"description":"Send a DM either to an existing conversation or straight to a user\n(opening the DM on first contact). Exactly one target is required.","properties":{"conversation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Conversation Id"},"recipient_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Recipient Id"},"body":{"maxLength":4000,"minLength":1,"title":"Body","type":"string"}},"required":["body"],"title":"SendMessagePayload","type":"object"}},"set_active_host":{"name":"set_active_host","title":"set_active_host","summary":"Active host hands the role to another active participant.","payload":{"description":"An action targeting another user in the room (host moderation, or a\nmember inviting someone into a private room).","properties":{"live_id":{"title":"Live Id","type":"integer"},"user_id":{"title":"User Id","type":"integer"}},"required":["live_id","user_id"],"title":"LiveUserActionPayload","type":"object"}},"typing":{"name":"typing","title":"typing","summary":"Fan out a transient typing indicator to the other members (never persisted — the socket is its only home).","payload":{"properties":{"conversation_id":{"title":"Conversation Id","type":"integer"},"is_typing":{"default":true,"title":"Is Typing","type":"boolean"}},"required":["conversation_id"],"title":"TypingPayload","type":"object"}},"update_media_state":{"name":"update_media_state","title":"update_media_state","summary":"Fan out transient device state (mic/camera/facing/network). These are deliberately never persisted — the socket is their only home.","payload":{"description":"Transient device state, fanned out but never persisted.","properties":{"live_id":{"title":"Live Id","type":"integer"},"mic_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"default":null,"title":"Mic Enabled"},"camera_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"default":null,"title":"Camera Enabled"},"camera_facing":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Camera Facing"},"network_quality":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Network Quality"}},"required":["live_id"],"title":"MediaStatePayload","type":"object"}},"accepted_live_join_request":{"name":"accepted_live_join_request","title":"accepted_live_join_request","summary":"Ack to the host after approving a request.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","accepted_user_id":"<uuid>"}}]},"active_host_set":{"name":"active_host_set","title":"active_host_set","summary":"Hostship transferred; sent to the room.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","active_host_id":"<uuid>","active_host":{"id":"<uuid>","display_name":"Bob"}}}]},"authenticated":{"name":"authenticated","title":"authenticated","summary":"Connection accepted (sent only to the connecting client).","payload":{"type":"object"},"examples":[{"payload":{"user_id":"<uuid>","message":"Authentication successful."}}]},"call_accepted":{"name":"call_accepted","title":"call_accepted","summary":"Sent to the caller when the callee answers.","payload":{"type":"object"},"examples":[{"payload":{"call_id":"<uuid>","callee":{"id":"<uuid>","display_name":"Bob"}}}]},"call_cancelled":{"name":"call_cancelled","title":"call_cancelled","summary":"Sent to the callee when the caller hangs up before connecting.","payload":{"type":"object"},"examples":[{"payload":{"call_id":"<uuid>"}}]},"call_connected":{"name":"call_connected","title":"call_connected","summary":"Private ack to the callee with their LiveKit token on accept.","payload":{"type":"object"},"examples":[{"payload":{"call":{"id":"<uuid>","status":"ongoing"},"token":"<livekit-jwt>","livekit_url":"ws://localhost:7880"}}]},"call_ended":{"name":"call_ended","title":"call_ended","summary":"Sent to the other party when a connected call ends.","payload":{"type":"object"},"examples":[{"payload":{"call_id":"<uuid>"}}]},"call_rejected":{"name":"call_rejected","title":"call_rejected","summary":"Sent to the caller when the callee declines.","payload":{"type":"object"},"examples":[{"payload":{"call_id":"<uuid>"}}]},"call_ringing":{"name":"call_ringing","title":"call_ringing","summary":"Private ack to the caller with their LiveKit token while the callee is rung.","payload":{"type":"object"},"examples":[{"payload":{"call":{"id":"<uuid>","status":"ringing"},"token":"<livekit-jwt>","livekit_url":"ws://localhost:7880"}}]},"error":{"name":"error","title":"error","summary":"An error for the caller (bad payload, unknown event, permission denied, …).","payload":{"type":"object"},"examples":[{"payload":{"message":"Only the active host can manage this stream"}}]},"gift_received":{"name":"gift_received","title":"gift_received","summary":"A gift was sent to the room's host; fanned out to everyone in the room so clients can play the animation.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","gift":{"id":"<uuid>","code":"rose","name":"Rose","asset_url":"https://cdn/…/rose.svga","effect":"hearts"},"quantity":2,"total_price":200,"sender":{"id":"<uuid>","display_name":"Ada"},"recipient_id":"<uuid>"}}]},"host_left_live":{"name":"host_left_live","title":"host_left_live","summary":"The active host stepped out; sent to the room.","payload":{"type":"object"},"examples":[{"payload":{"left_user":"<uuid>","host_left":true}}]},"incoming_call":{"name":"incoming_call","title":"incoming_call","summary":"Sent to the callee: someone is calling. No token yet — the callee accepts to receive one.","payload":{"type":"object"},"examples":[{"payload":{"call":{"id":"<uuid>","caller_id":"<uuid>","callee_id":"<uuid>","call_type":"audio","status":"ringing"},"caller":{"id":"<uuid>","display_name":"Ada"}}}]},"join_live_request_sent":{"name":"join_live_request_sent","title":"join_live_request_sent","summary":"Ack to the requester that their join request was sent.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>"}}]},"joined_live":{"name":"joined_live","title":"joined_live","summary":"Private ack to the joiner carrying the scoped LiveKit token.","payload":{"type":"object"},"examples":[{"payload":{"stream":{"id":"<uuid>","room_name":"live-…","status":"live"},"token":"<livekit-jwt>","livekit_url":"ws://localhost:7880","identity":"<uuid>"}}]},"kicked_successfully":{"name":"kicked_successfully","title":"kicked_successfully","summary":"Ack to the host after kicking a user.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","kicked_user_id":"<uuid>"}}]},"live_ended":{"name":"live_ended","title":"live_ended","summary":"The room was ended by its active host; sent to the room.","payload":{"type":"object"},"examples":[{"payload":{"live_ended":true,"live_id":"<uuid>"}}]},"live_invite_accepted":{"name":"live_invite_accepted","title":"live_invite_accepted","summary":"Sent to the inviter when the invitee accepts.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","invitee_id":"<uuid>"}}]},"live_invite_declined":{"name":"live_invite_declined","title":"live_invite_declined","summary":"Sent to the inviter when the invitee declines.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","invitee_id":"<uuid>"}}]},"live_invite_received":{"name":"live_invite_received","title":"live_invite_received","summary":"Sent to the invitee: a member invited you into a private room. Accept, then join.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","inviter":{"id":"<uuid>"}}}]},"live_invite_sent":{"name":"live_invite_sent","title":"live_invite_sent","summary":"Ack to the inviter after inviting someone to a private room.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","invitee_id":"<uuid>"}}]},"live_join_request_received":{"name":"live_join_request_received","title":"live_join_request_received","summary":"Sent to the active host with the requester's profile.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","requester":{"id":"<uuid>","display_name":"Ada"}}}]},"live_started":{"name":"live_started","title":"live_started","summary":"A followed host went live; sent to each of their followers' personal rooms (FR-NOTIF-01).","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","room_name":"live-…","category":"video","host":{"id":"<uuid>","display_name":"Ada"}}}]},"media_state_changed":{"name":"media_state_changed","title":"media_state_changed","summary":"A participant's transient device state (never persisted); fanned out to the room except the sender.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","user_id":"<uuid>","mic_enabled":false,"camera_enabled":true,"camera_facing":"front","network_quality":"good"}}]},"message_deleted":{"name":"message_deleted","title":"message_deleted","summary":"A message was deleted; sent to the thread (and as the deleter's ack).","payload":{"type":"object"},"examples":[{"payload":{"conversation_id":"<uuid>","message_id":"<uuid>"}}]},"message_read":{"name":"message_read","title":"message_read","summary":"A member read the thread; sent to the other members.","payload":{"type":"object"},"examples":[{"payload":{"conversation_id":"<uuid>","reader_id":"<uuid>","read_at":"<iso-8601>"}}]},"message_sent":{"name":"message_sent","title":"message_sent","summary":"Private ack to the sender with the persisted message.","payload":{"type":"object"},"examples":[{"payload":{"id":"<uuid>","conversation_id":"<uuid>","sender_id":"<uuid>","body":"hey!","is_deleted":false,"created_at":"<iso-8601>"}}]},"new_message":{"name":"new_message","title":"new_message","summary":"A new message; sent to every conversation member except the sender.","payload":{"type":"object"},"examples":[{"payload":{"id":"<uuid>","conversation_id":"<uuid>","sender_id":"<uuid>","body":"hey!","is_deleted":false,"created_at":"<iso-8601>"}}]},"rejected_live_join_request":{"name":"rejected_live_join_request","title":"rejected_live_join_request","summary":"Ack to the host after rejecting a request.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","rejected_user_id":"<uuid>"}}]},"request_join_live_accepted":{"name":"request_join_live_accepted","title":"request_join_live_accepted","summary":"Sent to the requester when the host approves.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","accepted_by":"<uuid>"}}]},"request_join_live_rejected":{"name":"request_join_live_rejected","title":"request_join_live_rejected","summary":"Sent to the requester when the host rejects.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","rejected_by":"<uuid>"}}]},"role_changed":{"name":"role_changed","title":"role_changed","summary":"A user's org role changed (agent/host granted, detached or inserted); fanned to everyone so apps re-render.","payload":{"type":"object"},"examples":[{"payload":{"user_id":"<uuid>","role":"host"}}]},"user_joined_live":{"name":"user_joined_live","title":"user_joined_live","summary":"A participant joined; sent to the room (except the joiner). Payload is the public user profile plus `live_id`.","payload":{"type":"object"},"examples":[{"payload":{"id":"<uuid>","display_name":"Ada","role":"user","is_online":true,"live_id":"<uuid>"}}]},"user_left_live":{"name":"user_left_live","title":"user_left_live","summary":"A non-host participant left; sent to the room.","payload":{"type":"object"},"examples":[{"payload":{"left_user":"<uuid>","host_left":false}}]},"user_offline":{"name":"user_offline","title":"user_offline","summary":"Broadcast to everyone when a user's last socket drops.","payload":{"type":"object"},"examples":[{"payload":{"user_id":"<uuid>"}}]},"user_online":{"name":"user_online","title":"user_online","summary":"Broadcast to everyone when a user connects.","payload":{"type":"object"},"examples":[{"payload":{"user_id":"<uuid>"}}]},"user_typing":{"name":"user_typing","title":"user_typing","summary":"Transient typing indicator (never persisted); sent to the other members.","payload":{"type":"object"},"examples":[{"payload":{"conversation_id":"<uuid>","user_id":"<uuid>","is_typing":true}}]},"you_kicked":{"name":"you_kicked","title":"you_kicked","summary":"Sent to a user when the host removes them from the room.","payload":{"type":"object"},"examples":[{"payload":{"live_id":"<uuid>","kicked_by":"<uuid>"}}]}}}}