{ "openapi": "3.1.0", "info": { "title": "Serengo API", "description": "API for Serengo, a location-based social discovery platform where users can share 'finds' (posts) at locations, connect with friends, and discover new places.", "version": "1.0.0" }, "servers": [ { "url": "https://serengo.zias.be/" } ], "security": [ { "bearerAuth": [] } ], "paths": { "/api/locations": { "get": { "summary": "Get locations with finds", "parameters": [ { "name": "lat", "in": "query", "schema": { "type": "number" }, "description": "Latitude for radius search" }, { "name": "lng", "in": "query", "schema": { "type": "number" }, "description": "Longitude for radius search" }, { "name": "radius", "in": "query", "schema": { "type": "integer", "default": 50 }, "description": "Search radius in km" }, { "name": "includePrivate", "in": "query", "schema": { "type": "boolean" }, "description": "Include private finds" }, { "name": "includeFriends", "in": "query", "schema": { "type": "boolean" }, "description": "Include friends' private finds" }, { "name": "order", "in": "query", "schema": { "type": "string", "enum": ["desc", "asc"], "default": "desc" }, "description": "Sort order" } ], "responses": { "200": { "description": "Locations with finds", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LocationWithFinds" } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Create a new location", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["latitude", "longitude"], "properties": { "latitude": { "type": "number" }, "longitude": { "type": "number" }, "locationName": { "type": "string" } } } } } }, "responses": { "200": { "description": "Location created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Location" } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds": { "get": { "summary": "Get finds for a location", "parameters": [ { "name": "locationId", "in": "query", "required": true, "schema": { "type": "string" }, "description": "ID of the location" }, { "name": "includePrivate", "in": "query", "schema": { "type": "boolean" } }, { "name": "includeFriends", "in": "query", "schema": { "type": "boolean" } }, { "name": "order", "in": "query", "schema": { "type": "string", "enum": ["desc", "asc"], "default": "desc" } } ], "responses": { "200": { "description": "Finds for the location", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Find" } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Create a new find", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["locationId", "title"], "properties": { "locationId": { "type": "string" }, "title": { "type": "string", "maxLength": 100 }, "description": { "type": "string", "maxLength": 500 }, "category": { "type": "string" }, "isPublic": { "type": "boolean" }, "media": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string" }, "url": { "type": "string" }, "thumbnailUrl": { "type": "string" } } } } } } } } }, "responses": { "200": { "description": "Find created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Find" } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/{findId}": { "get": { "summary": "Get a specific find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Find details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Find" } } } } }, "security": [{ "bearerAuth": [] }] }, "put": { "summary": "Update a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string", "maxLength": 100 }, "description": { "type": "string", "maxLength": 500 }, "category": { "type": "string" }, "isPublic": { "type": "boolean" }, "media": { "type": "array", "items": { "$ref": "#/components/schemas/Media" } }, "mediaToDelete": { "type": "array", "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Find updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Find" } } } } }, "security": [{ "bearerAuth": [] }] }, "delete": { "summary": "Delete a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Find deleted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/{findId}/comments": { "get": { "summary": "Get comments for a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Comments", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Add a comment to a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["content"], "properties": { "content": { "type": "string", "maxLength": 500 } } } } } }, "responses": { "200": { "description": "Comment added", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Comment" } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/{findId}/like": { "post": { "summary": "Like a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Like added", "content": { "application/json": { "schema": { "type": "object", "properties": { "likeCount": { "type": "integer" } } } } } } }, "security": [{ "bearerAuth": [] }] }, "delete": { "summary": "Unlike a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Like removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "likeCount": { "type": "integer" } } } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/{findId}/media/{mediaId}": { "delete": { "summary": "Delete specific media from a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "mediaId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Media deleted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/{findId}/rate": { "get": { "summary": "Get user's rating for a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "User's rating", "content": { "application/json": { "schema": { "type": "object", "properties": { "rating": { "type": "number", "nullable": true } } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Rate a find", "parameters": [ { "name": "findId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["rating"], "properties": { "rating": { "type": "number", "minimum": 1, "maximum": 5 } } } } } }, "responses": { "200": { "description": "Rating submitted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/comments/{commentId}": { "delete": { "summary": "Delete a comment", "parameters": [ { "name": "commentId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Comment deleted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/finds/upload": { "post": { "summary": "Upload media files for a find", "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "files": { "type": "array", "items": { "type": "string", "format": "binary" }, "minItems": 1, "maxItems": 5 }, "findId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Upload successful", "content": { "application/json": { "schema": { "type": "object", "properties": { "findId": { "type": "string" }, "media": { "type": "array", "items": { "$ref": "#/components/schemas/Media" } } } } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/friends": { "get": { "summary": "Get user's friendships", "parameters": [ { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["accepted", "pending", "blocked"], "default": "accepted" } }, { "name": "type", "in": "query", "schema": { "type": "string", "enum": ["friends", "sent", "received"], "default": "friends" } } ], "responses": { "200": { "description": "Friendships", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Friendship" } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Send a friend request", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["friendId"], "properties": { "friendId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Friend request sent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Friendship" } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/friends/{friendshipId}": { "put": { "summary": "Update friendship status", "parameters": [ { "name": "friendshipId", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["action"], "properties": { "action": { "type": "string", "enum": ["accept", "decline", "block"] } } } } } }, "responses": { "200": { "description": "Friendship updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Friendship" } } } } }, "security": [{ "bearerAuth": [] }] }, "delete": { "summary": "Remove friendship", "parameters": [ { "name": "friendshipId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Friendship removed" } }, "security": [{ "bearerAuth": [] }] } }, "/api/media/{path}": { "get": { "summary": "Serve media files", "parameters": [ { "name": "path", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Media file path" } ], "responses": { "200": { "description": "Media file", "content": { "*/*": { "schema": { "type": "string", "format": "binary" } } } } } }, "options": { "summary": "CORS preflight", "responses": { "200": { "description": "OK" } } } }, "/api/notifications": { "get": { "summary": "Get user notifications", "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20 } }, { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }, { "name": "unreadOnly", "in": "query", "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "Notifications", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Notification" } } } } } }, "security": [{ "bearerAuth": [] }] }, "patch": { "summary": "Mark notifications as read", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "notificationIds": { "type": "array", "items": { "type": "string" } }, "markAll": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Notifications marked as read" } }, "security": [{ "bearerAuth": [] }] }, "delete": { "summary": "Delete notifications", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "notificationId": { "type": "string" }, "deleteAll": { "type": "boolean" } } } } } }, "responses": { "204": { "description": "Notifications deleted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/notifications/count": { "get": { "summary": "Get unread notification count", "responses": { "200": { "description": "Unread count", "content": { "application/json": { "schema": { "type": "object", "properties": { "count": { "type": "integer" } } } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/notifications/preferences": { "get": { "summary": "Get notification preferences", "responses": { "200": { "description": "Preferences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Update notification preferences", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationPreferences" } } } }, "responses": { "200": { "description": "Preferences updated" } }, "security": [{ "bearerAuth": [] }] } }, "/api/notifications/subscribe": { "get": { "summary": "Get VAPID public key", "responses": { "200": { "description": "VAPID key", "content": { "application/json": { "schema": { "type": "object", "properties": { "publicKey": { "type": "string" } } } } } } }, "security": [{ "bearerAuth": [] }] }, "post": { "summary": "Subscribe to push notifications", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["subscription"], "properties": { "subscription": { "type": "object" } } } } } }, "responses": { "200": { "description": "Subscribed" } }, "security": [{ "bearerAuth": [] }] }, "delete": { "summary": "Unsubscribe from push notifications", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["endpoint"], "properties": { "endpoint": { "type": "string" } } } } } }, "responses": { "200": { "description": "Unsubscribed" } }, "security": [{ "bearerAuth": [] }] } }, "/api/places": { "get": { "summary": "Query Google Places API", "parameters": [ { "name": "action", "in": "query", "required": true, "schema": { "type": "string", "enum": ["search", "autocomplete", "details", "nearby"] } }, { "name": "query", "in": "query", "schema": { "type": "string" } }, { "name": "placeId", "in": "query", "schema": { "type": "string" } }, { "name": "lat", "in": "query", "schema": { "type": "number" } }, { "name": "lng", "in": "query", "schema": { "type": "number" } }, { "name": "radius", "in": "query", "schema": { "type": "integer", "default": 5000 } }, { "name": "type", "in": "query", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Places data", "content": { "application/json": { "schema": { "type": "object" } } } } }, "security": [{ "bearerAuth": [] }] } }, "/api/profile-picture/delete": { "delete": { "summary": "Delete profile picture", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["userId"], "properties": { "userId": { "type": "string" } } } } } }, "responses": { "204": { "description": "Profile picture deleted" } }, "security": [{ "bearerAuth": [] }] } }, "/api/profile-picture/upload": { "post": { "summary": "Upload profile picture", "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" }, "userId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Upload successful" } }, "security": [{ "bearerAuth": [] }] } }, "/api/users": { "get": { "summary": "Search users", "parameters": [ { "name": "q", "in": "query", "required": true, "schema": { "type": "string", "minLength": 2 } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 50 } } ], "responses": { "200": { "description": "Users", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/User" } } } } } }, "security": [{ "bearerAuth": [] }] } } }, "components": { "schemas": { "User": { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "profilePicture": { "type": "string", "nullable": true } } }, "Find": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "description": { "type": "string", "nullable": true }, "category": { "type": "string", "nullable": true }, "isPublic": { "type": "boolean" }, "locationId": { "type": "string" }, "userId": { "type": "string" }, "media": { "type": "array", "items": { "$ref": "#/components/schemas/Media" } }, "createdAt": { "type": "string", "format": "date-time" }, "rating": { "type": "number" }, "likeCount": { "type": "integer" }, "commentCount": { "type": "integer" }, "isLiked": { "type": "boolean" } } }, "Media": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": ["image", "video"] }, "url": { "type": "string" }, "thumbnailUrl": { "type": "string" } } }, "Location": { "type": "object", "properties": { "id": { "type": "string" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "name": { "type": "string", "nullable": true }, "averageRating": { "type": "number" }, "findCount": { "type": "integer" } } }, "LocationWithFinds": { "type": "object", "properties": { "id": { "type": "string" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "name": { "type": "string", "nullable": true }, "finds": { "type": "array", "items": { "$ref": "#/components/schemas/Find" } } } }, "Comment": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "userId": { "type": "string" }, "findId": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "user": { "$ref": "#/components/schemas/User" } } }, "Friendship": { "type": "object", "properties": { "id": { "type": "string" }, "requesterId": { "type": "string" }, "addresseeId": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "accepted", "blocked"] }, "requester": { "$ref": "#/components/schemas/User" }, "addressee": { "$ref": "#/components/schemas/User" } } }, "Notification": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string" }, "message": { "type": "string" }, "read": { "type": "boolean" }, "createdAt": { "type": "string", "format": "date-time" } } }, "NotificationPreferences": { "type": "object", "properties": { "friendRequests": { "type": "boolean" }, "friendAccepted": { "type": "boolean" }, "findLiked": { "type": "boolean" }, "findCommented": { "type": "boolean" }, "pushEnabled": { "type": "boolean" } } }, "Error": { "type": "object", "properties": { "error": { "type": "integer" }, "message": { "type": "string" } } } }, "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer" } } } }