{"openapi":"3.1.0","info":{"title":"Messenger REST API Reference","description":"This reference documents endpoints, authentication requirements, request and response schemas, and\nerrors of the REST API.\n\nSee the [README](https://github.com/stebeus/messenger-api/blob/main/README.md) first for an overview of the application, its features, and the WebSocket events.\n","version":"1.0.0","license":{"name":"MIT","url":"https://opensource.org/license/mit"}},"externalDocs":{"description":"README","url":"https://github.com/stebeus/messenger-api/blob/main/README.md"},"servers":[{"url":"https://messenger-api-laxw.onrender.com"}],"tags":[{"name":"Authentication","description":"Create an account to get a session cookie. You'll use it to access the REST and WebSocket functionality."},{"name":"Users","description":"Operations for searching users."},{"name":"Friend requests","description":"Operations for managing friend requests."},{"name":"Friends","description":"Operations for managing friendships."},{"name":"Conversations","description":"Operations for connecting to chat rooms and accessing messages."},{"name":"Direct messages","description":"Operations for searching direct messages (DMs)."},{"name":"Groups","description":"Operations for managing groups."},{"name":"Members","description":"Operations for managing conversation membership."},{"name":"Messages","description":"Operations for editing and deleting your messages."},{"name":"Group messages","description":"Operations for editing and deleting group messages."},{"name":"Bans","description":"Operations for managing group bans."}],"x-tagGroups":[{"name":"Authentication","tags":["Authentication"]},{"name":"Social","tags":["Users","Friend requests","Friends"]},{"name":"Messaging","tags":["Conversations","Messages","Direct messages","Groups","Members","Group messages","Bans"]}],"components":{},"paths":{"/api/v1/users":{"get":{"operationId":"List_users","description":"Retrieves users matching the specified query.","tags":["Users"],"responses":{"200":{"description":"Users matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"groups":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]}},"memberships":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}}},"required":["createdAt","updatedAt","id","username","groups","memberships"]}},"example":[{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":"","groups":[{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}],"memberships":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}]}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List users"}},"/api/v1/users/{userId}":{"get":{"operationId":"Get_user","description":"Retrieves the specified user.","tags":["Users"],"responses":{"200":{"description":"The specified user.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"groups":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]}},"memberships":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}}},"required":["createdAt","updatedAt","id","username","groups","memberships"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":"","groups":[{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}],"memberships":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}]}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"User not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"userId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Get user"}},"/api/v1/friends":{"get":{"operationId":"List_friends","description":"Retrieves friends matching the specified query.","tags":["Friends"],"responses":{"200":{"description":"Friends matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"user1Id":{"type":"string","pattern":"^[1-9]\\d*$"},"user2Id":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"},"friend":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]}},"required":["user1Id","user2Id","createdAt","friend"]}},"example":[{"user1Id":"string","user2Id":"string","createdAt":"string","friend":{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":""}}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List friends"}},"/api/v1/friends/{requesterId}":{"post":{"operationId":"Accept_friend_request","description":"Accepts a friend request and creates a DM for the friends.","tags":["Friends"],"responses":{"201":{"description":"The new friendship.","content":{"application/json":{"schema":{"type":"object","properties":{"user1Id":{"type":"string","pattern":"^[1-9]\\d*$"},"user2Id":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"}},"required":["user1Id","user2Id","createdAt"]},"example":{"user1Id":"string","user2Id":"string","createdAt":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"Friend request not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Friend request not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"requesterId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Accept friend request"}},"/api/v1/friends/{friendId}":{"delete":{"operationId":"Unfriend_user","description":"Unfriends a user.","tags":["Friends"],"responses":{"200":{"description":"The unfriended user.","content":{"application/json":{"schema":{"type":"object","properties":{"user1Id":{"type":"string","pattern":"^[1-9]\\d*$"},"user2Id":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"}},"required":["user1Id","user2Id","createdAt"]},"example":{"user1Id":"string","user2Id":"string","createdAt":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"Friend not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Friendship not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"friendId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Unfriend user"}},"/api/v1/friend-requests":{"get":{"operationId":"List_friend_requests","description":"Retrieves friend requests matching the specified query.","tags":["Friend requests"],"responses":{"200":{"description":"Friend requests matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"requesterId":{"type":"string","pattern":"^[1-9]\\d*$"},"recipientId":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"},"requester":{"anyOf":[{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]},{"type":"null"}]},"recipient":{"anyOf":[{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]},{"type":"null"}]}},"required":["requesterId","recipientId","createdAt","requester","recipient"]}},"example":[{"requesterId":"string","recipientId":"string","createdAt":"string","requester":"","recipient":""}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"},{"in":"query","name":"direction","schema":{"type":"string","enum":["incoming","outgoing"]},"example":"incoming","description":"Filter for incoming or outgoing friend requests."}],"summary":"List friend requests"}},"/api/v1/friend-requests/{recipientId}":{"post":{"operationId":"Send_friend_request","description":"Sends a friend request to another user.","tags":["Friend requests"],"responses":{"201":{"description":"The sent friend request.","content":{"application/json":{"schema":{"type":"object","properties":{"requesterId":{"type":"string","pattern":"^[1-9]\\d*$"},"recipientId":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"}},"required":["requesterId","recipientId","createdAt"]},"example":{"requesterId":"string","recipientId":"string","createdAt":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"Recipient user not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"User not found"}},"required":["status","message"]}}}},"409":{"description":"A friend request already exists or the users are already friends.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":409},"message":{"type":"string","const":"Friend request already exists"}},"required":["status","message"]},"examples":{"Existing friend request":{"value":{"status":409,"message":"Friend request already exists"}},"Existing friendship":{"value":{"status":409,"message":"Friendship already exists"}}}}}},"422":{"description":"A user cannot send a friend request to themselves.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":422},"message":{"type":"string","const":"Cannot send a friend request to yourself"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"recipientId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Send friend request"}},"/api/v1/friend-requests/{userId}":{"delete":{"operationId":"Cancel_friend_request","description":"Cancels a sent or received friend request.","tags":["Friend requests"],"responses":{"200":{"description":"The cancelled friend request.","content":{"application/json":{"schema":{"type":"object","properties":{"requesterId":{"type":"string","pattern":"^[1-9]\\d*$"},"recipientId":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"}},"required":["requesterId","recipientId","createdAt"]},"example":{"requesterId":"string","recipientId":"string","createdAt":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"Friend request not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Friend request not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"userId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Cancel friend request"}},"/api/v1/conversations/{conversationId}/ws":{"get":{"operationId":"Chat_room_HTTP_errors","description":"It validates, authenticates, and verifies the chat room existence before connecting to its WebSocket.","tags":["Conversations"],"responses":{"400":{"description":"Invalid conversation ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"Conversation not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Conversation not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"conversationId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Chat room HTTP errors"}},"/api/v1/conversations/{conversationId}/messages":{"get":{"operationId":"List_messages","description":"Retrieves messages matching the specified query.","tags":["Conversations"],"responses":{"200":{"description":"Messages matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000},"sender":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]}},"required":["createdAt","updatedAt","id","senderId","conversationId","content","sender"]}},"example":[{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string","sender":{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":""}}]}}},"400":{"description":"Invalid conversation ID or query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Membership is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"conversationId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List messages"},"post":{"operationId":"Send_message","description":"Sends a message to the specified conversation.","tags":["Conversations"],"responses":{"201":{"description":"The sent message.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}}}},"400":{"description":"Invalid conversation ID parameter or message content.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Membership is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"conversationId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["content"]},"example":{"content":"Hello, world!"}}},"description":null},"summary":"Send message"}},"/api/v1/messages/{messageId}":{"patch":{"operationId":"Edit_message","description":"Edits the specified sent message.","tags":["Messages"],"responses":{"200":{"description":"The edited message.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}}}},"400":{"description":"Invalid ID parameter or body.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You cannot edit messages sent by other users.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Message not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Message not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"messageId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":1000}}},"example":{"content":"Goodbye, world!"}}},"description":null},"summary":"Edit message"},"delete":{"operationId":"Delete_message","description":"Deletes the specified sent message.","tags":["Messages"],"responses":{"200":{"description":"The deleted message.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You cannot delete messages sent by other users.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Message not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Message not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"messageId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Delete message"}},"/api/v1/dms":{"get":{"operationId":"List_DMs","description":"Retrieves DMs involving users matching the specified username or display name, with optional sorting.","tags":["Direct messages"],"responses":{"200":{"description":"DMs matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"},"members":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}},"messages":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]}}},"required":["id","createdAt","members","messages"]}},"example":[{"id":"string","createdAt":"string","members":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}],"messages":[{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}]}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"},"description":"Search by username or display name."},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List DMs"}},"/api/v1/dms/{dmId}":{"get":{"operationId":"Get_DM","description":"Retrieves the specified DM.","tags":["Direct messages"],"responses":{"200":{"description":"The specified DM.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","pattern":"^[1-9]\\d*$"},"createdAt":{"type":"string","format":"date-time"},"members":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}},"messages":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]}}},"required":["id","createdAt","members","messages"]},"example":{"id":"string","createdAt":"string","members":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}],"messages":[{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}]}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"404":{"description":"DM not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Direct message not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"dmId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Get DM"}},"/api/v1/groups/{groupId}/bans":{"get":{"operationId":"List_bans","description":"Retrieves bans matching the specified query.","tags":["Bans"],"responses":{"200":{"description":"Bans matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"groupId":{"type":"string","pattern":"^[1-9]\\d*$"},"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"user":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]},"group":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]}},"required":["createdAt","updatedAt","userId","groupId","reason","user","group"]}},"example":[{"createdAt":"string","updatedAt":"string","userId":"string","groupId":"string","reason":"string","expiresAt":"","user":{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":""},"group":{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}}]}}},"400":{"description":"Invalid group ID or query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to view bans.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List bans"}},"/api/v1/groups/{groupId}/bans/{memberId}":{"post":{"operationId":"Ban_member","description":"Bans the specified group member.","tags":["Bans"],"responses":{"201":{"description":"The banned user.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"groupId":{"type":"string","pattern":"^[1-9]\\d*$"},"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["createdAt","updatedAt","userId","groupId","reason"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","groupId":"string","reason":"string","expiresAt":""}}}},"400":{"description":"Invalid ID parameters or body.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to ban this member.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Member not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Member not found"}},"required":["status","message"]}}}},"409":{"description":"User is already banned.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":409},"message":{"type":"string","const":"User is already banned"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"memberId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["reason"]},"example":{"reason":"You suck.","expiresAt":""}}},"description":null},"summary":"Ban member"},"patch":{"operationId":"Update_ban","description":"Updates the specified ban.","tags":["Bans"],"responses":{"200":{"description":"The updated ban.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"groupId":{"type":"string","pattern":"^[1-9]\\d*$"},"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["createdAt","updatedAt","userId","groupId","reason"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","groupId":"string","reason":"string","expiresAt":""}}}},"400":{"description":"Invalid ID parameters or body.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to update this ban.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Ban not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Ban not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"memberId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}}},"example":{"reason":"You still suck.","expiresAt":"2026-10-31"}}},"description":null},"summary":"Update ban"},"delete":{"operationId":"Unban_user","description":"Unbans the specified user.","tags":["Bans"],"responses":{"200":{"description":"The unbanned user.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"groupId":{"type":"string","pattern":"^[1-9]\\d*$"},"reason":{"type":"string","minLength":1,"maxLength":250},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["createdAt","updatedAt","userId","groupId","reason"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","groupId":"string","reason":"string","expiresAt":""}}}},"400":{"description":"Invalid ID parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to unban this user.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Ban not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Ban not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"memberId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Unban user"}},"/api/v1/groups/{groupId}/members":{"get":{"operationId":"List_members","description":"Retrieves members matching the specified query.","tags":["Members"],"responses":{"200":{"description":"Members matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]},"user":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"username":{"type":"string","minLength":3,"maxLength":30,"pattern":"^[\\p{L}\\p{N}_]+$"},"displayName":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":250},{"type":"null"}]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]}},"required":["createdAt","updatedAt","id","username"]}},"required":["createdAt","updatedAt","userId","conversationId","user"]}},"example":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string","user":{"createdAt":"string","updatedAt":"string","id":"string","username":"string","displayName":"","bio":"","avatar":""}}]}}},"400":{"description":"Invalid group ID or query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Membership is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","name"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List members"},"post":{"operationId":"Join_group","description":"Joins the specified group.","tags":["Members"],"responses":{"201":{"description":"The joined group.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}}}},"400":{"description":"Invalid group ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You have been banned from this group.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"You have been banned from this group"},"details":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":250},"duration":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","const":"Permanent"}]}},"required":["reason","duration"]}},"required":["status","message","details"]}}}},"409":{"description":"Group already joined.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":409},"message":{"type":"string","const":"Member already exists"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Join group"}},"/api/v1/groups/{groupId}/members/me":{"delete":{"operationId":"Leave_group","description":"Leaves the specified group.","tags":["Members"],"responses":{"200":{"description":"The exited group.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}}}},"400":{"description":"Invalid group ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Owners cannot leave their own groups.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Leave group"}},"/api/v1/groups/{groupId}/members/{memberId}":{"patch":{"operationId":"Change_member_role","description":"Changes the specified member role.","tags":["Members"],"responses":{"200":{"description":"The updated member.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}}}},"400":{"description":"Invalid ID parameters or role.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to update this member.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Member not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Member not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"memberId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"default":"member","type":"string","enum":["member","admin"]}}},"example":{"role":"admin"}}},"description":null},"summary":"Change member role"},"delete":{"operationId":"Kick_member","description":"Kicks the specified member.","tags":["Members"],"responses":{"200":{"description":"The kicked user.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]},"example":{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}}}},"400":{"description":"Invalid ID parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to kick this member.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Member not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Member not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"memberId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Kick member"}},"/api/v1/groups/{groupId}/messages/{messageId}":{"patch":{"operationId":"Edit_group_message","description":"Edits the specified group message.","tags":["Group messages"],"responses":{"200":{"description":"The edited message.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}}}},"400":{"description":"Invalid ID parameters or message content.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to edit this message.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Group message not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Message not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"messageId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":1000}}},"example":{"content":"string"}}},"description":null},"summary":"Edit group message"},"delete":{"operationId":"Delete_group_message","description":"Deletes the specified group message.","tags":["Group messages"],"responses":{"200":{"description":"The deleted message.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]},"example":{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}}}},"400":{"description":"Invalid ID parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"You do not have permission to delete this message.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Group message not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Message not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"},{"in":"path","name":"messageId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Delete group message"}},"/api/v1/groups":{"get":{"operationId":"List_public_groups","description":"Retrieves public groups matching the specified query, where the current user did not join yet or get banned.","tags":["Groups"],"responses":{"200":{"description":"Public groups matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]},"members":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}}},"required":["createdAt","updatedAt","conversationId","ownerId","name","members"]}},"example":[{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string","members":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}]}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List public groups"},"post":{"operationId":"Create_group","description":"Creates a group.","tags":["Groups"],"responses":{"201":{"description":"The new group.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]},"example":{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}}}},"400":{"description":"Invalid body.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"413":{"description":"Avatar file size must not exceed 512 KB.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":413},"message":{"type":"string","const":"Avatar is too large"}},"required":["status","message"]}}}}},"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["name"]}}},"description":null},"summary":"Create group"}},"/api/v1/groups/me":{"get":{"operationId":"List_joined_groups","description":"Retrieves joined groups matching the specified query.","tags":["Groups"],"responses":{"200":{"description":"Joined groups matching the specified query.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]},"members":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"role":{"default":"member","type":"string","enum":["member","admin","owner"]}},"required":["createdAt","updatedAt","userId","conversationId"]}},"messages":{"type":"array","items":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"id":{"type":"string","pattern":"^[1-9]\\d*$"},"senderId":{"type":"string","pattern":"^[1-9]\\d*$"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"content":{"type":"string","minLength":1,"maxLength":1000}},"required":["createdAt","updatedAt","id","senderId","conversationId","content"]}}},"required":["createdAt","updatedAt","conversationId","ownerId","name","members","messages"]}},"example":[{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string","members":[{"createdAt":"string","updatedAt":"string","userId":"string","conversationId":"string","role":"string"}],"messages":[{"createdAt":"string","updatedAt":"string","id":"string","senderId":"string","conversationId":"string","content":"string"}]}]}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}}},"parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt"]},"example":"createdAt"},{"in":"query","name":"order","schema":{"default":"asc","type":"string","enum":["asc","desc"]},"example":"asc"}],"summary":"List joined groups"}},"/api/v1/groups/{groupId}":{"patch":{"operationId":"Update_group","description":"Updates an owned group.","tags":["Groups"],"responses":{"200":{"description":"The updated group.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]},"example":{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}}}},"400":{"description":"Invalid ID parameter or body.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Group ownership is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Group not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Group not found"}},"required":["status","message"]}}}},"413":{"description":"Avatar file size must not exceed 512 KB.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":413},"message":{"type":"string","const":"Avatar is too large"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{},"visibility":{"default":"private","type":"string","enum":["private","public"]}}}}},"description":null},"summary":"Update group"},"delete":{"operationId":"Delete_group","description":"Deletes an owned group.","tags":["Groups"],"responses":{"200":{"description":"The deleted group.","content":{"application/json":{"schema":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"conversationId":{"type":"string","pattern":"^[1-9]\\d*$"},"ownerId":{"type":"string","pattern":"^[1-9]\\d*$"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":["string","null"]},"avatar":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"visibility":{"default":"private","type":"string","enum":["private","public"]}},"required":["createdAt","updatedAt","conversationId","ownerId","name"]},"example":{"createdAt":"string","updatedAt":"string","conversationId":"string","ownerId":"string","name":"string","description":["string",null],"avatar":"","visibility":"string"}}}},"400":{"description":"Invalid ID parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":400},"message":{"type":"string","const":"Bad Request"},"details":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["status","message","details"]}}}},"401":{"description":"Authentication is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":401},"message":{"type":"string","const":"Unauthorized"}},"required":["status","message"]}}}},"403":{"description":"Group ownership is required.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":403},"message":{"type":"string","const":"Forbidden"}},"required":["status","message"]}}}},"404":{"description":"Group not found.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"number","const":404},"message":{"type":"string","const":"Group not found"}},"required":["status","message"]}}}}},"parameters":[{"in":"path","name":"groupId","schema":{"type":"string","pattern":"^[1-9]\\d*$"},"required":true,"example":"1"}],"summary":"Delete group"}},"/api/auth/sign-up/email":{"post":{"summary":"Sign up","description":"The API doesn't require your full name or email, but they are included because of a [Better Auth's limitation](https://better-auth.com/docs/reference/faq#can-i-remove-name-image-or-email-fields-from-the-user-table).","responses":{"200":{"description":"Successful response"}},"operationId":"Sign_up","tags":["Authentication"],"parameters":[{"name":"Origin","in":"header","schema":{"type":"string"},"example":"https://messenger-api-laxw.onrender.com"}],"requestBody":{"content":{"application/json":{"example":{"name":"John Doe","username":"your_username","email":"your_username@email.com","password":"your_password"}}}}}},"/api/auth/sign-in/username":{"post":{"summary":"Sign in","responses":{"200":{"description":"Successful response"}},"operationId":"Sign_in","tags":["Authentication"],"parameters":[{"name":"Origin","in":"header","schema":{"type":"string"},"example":"https://messenger-api-laxw.onrender.com"}],"requestBody":{"content":{"application/json":{"example":{"username":"your_username","password":"your_password"}}}}}},"/api/auth/get-session":{"get":{"summary":"Get session","responses":{"200":{"description":"Successful response"}},"operationId":"Get_session","tags":["Authentication"]}},"/api/auth/sign-out":{"post":{"summary":"Sign out","responses":{"200":{"description":"Successful response"}},"operationId":"Sign_out","tags":["Authentication"],"parameters":[{"name":"Origin","in":"header","schema":{"type":"string"},"example":"https://messenger-api-laxw.onrender.com"}],"requestBody":{"content":{"application/json":{"example":{}}}}}}}}