# Serena API docs ## Overview **Base URL:** `http://localhost:8080/api` ## Authentication The API uses Bearer token authentication. Include the token in the Authorization header: ``` Authorization: Bearer ``` ### Token Types - **Owner Token**: Generated when creating a radio station, allows full station management - **Client Token**: Generated when joining a station, allows participation in the station ## API Endpoints ### Radio Station Management #### Create Radio Station #### Get All Radio Stations #### Get Radio Station by ID #### Delete Radio Station ### Client Management #### Connect Client to Station ### Song Queue Management #### Add Song to Client's Preferred Queue #### Get Radio Station Queue #### Get Recommended Queue ## Radio Station Management #### Create Radio Station Creates a new radio station and returns an owner token. **Endpoint:** `POST /radio-stations` **Request Body:** ```json { "name": "My Awesome Station", "description": "The best music station ever" } ``` **Response:** ```json { "success": true, "message": "Radio station created successfully", "data": { "station": { "id": "station-uuid", "name": "My Awesome Station", "description": "The best music station ever", "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", "connectedClients": [] }, "ownerToken": "jwt-token-here", "message": "Radio station created successfully. Use this token to manage your station." } } ``` #### Get All Radio Stations Retrieves all radio stations. Requires authentication. **Endpoint:** `GET /radio-stations` **Response:** ```json { "success": true, "message": "Success", "data": [ { "id": "station-uuid", "name": "Station Name", "description": "Station Description", "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", "connectedClients": [] } ] } ``` #### Get Radio Station by ID Retrieves a specific radio station. Requires authentication. **Endpoint:** `GET /radio-stations/{stationId}` **Response:** ```json { "success": true, "message": "Success", "data": { "id": "station-uuid", "name": "Station Name", "description": "Station Description", "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", "connectedClients": [] } } ``` #### Delete Radio Station Deletes a radio station. Only the station owner can delete it. **Endpoint:** `DELETE /radio-stations/{stationId}` **Response:** ```json { "success": true, "message": "Radio station deleted successfully", "data": null } ``` ### Client Management #### Connect Client to Station Connects a client to a radio station using a join code. No authentication required. **Endpoint:** `POST /clients/connect` **Request Body (Option 1 - Using station ID and join code):** ```json { "username": "john_doe", "radioStationId": "station-uuid", "joinCode": "ABC123" } ``` **Request Body (Option 2 - Using join code only):** ```json { "username": "john_doe", "joinCode": "ABC123" } ``` **Response:** ```json { "success": true, "message": "Successfully connected to radio station", "data": { "client": { "id": "client-uuid", "username": "john_doe", "radioStationId": "station-uuid", "connectedAt": "2025-08-01T10:00:00" }, "clientToken": "jwt-token-here", "message": "Successfully connected to radio station. Use this token for further requests." } } ``` ### Song Queue Management #### Add Song to Client's Preferred Queue Adds a song to a specific client's preferred queue. The frontend can merge track and audio features objects using `const merged = { ...trackObj, ...audioFeaturesObj };` **Endpoint:** `POST /api/songs/queue` **Request Body:** ```json { "song": { "id": "4iV5W9uYEdYUVa79Axb7Rh", "popularity": 85, "tempo": 120.5, "danceability": 0.8, "energy": 0.7, "valence": 0.6, "acousticness": 0.1, "instrumentalness": 0.0, "liveness": 0.1, "speechiness": 0.04 }, "clientId": "client-uuid", "radioStationId": "station-uuid" } ``` **Response:** ```json { "success": true, "message": "Song added to client's preferred queue successfully", "data": null } ``` #### Get Radio Station Queue Retrieves the main song queue for a radio station. Returns a list of song objects. **Endpoint:** `GET /api/songs/queue?radioStationId={radioStationId}` **Query Parameters:** - `radioStationId` (required): The ID of the radio station **Response:** ```json { "success": true, "message": "Queue retrieved successfully", "data": [ { "id": "4iV5W9uYEdYUVa79Axb7Rh", "popularity": 85, "tempo": 120.5, "danceability": 0.8, "energy": 0.7, "valence": 0.6, "acousticness": 0.1, "instrumentalness": 0.0, "liveness": 0.1, "speechiness": 0.04 }, { "id": "7ouMYWpwJ422jRcDASZB7P", "popularity": 78, "tempo": 95.0, "danceability": 0.6, "energy": 0.5, "valence": 0.8, "acousticness": 0.3, "instrumentalness": 0.0, "liveness": 0.2, "speechiness": 0.06 } ] } ``` #### Get Recommended Queue **Endpoint:** `GET /api/songs/queue/recommended?radioStationId={radioStationId}¤tSongId={currentSongId}` **Query Parameters:** - `radioStationId` (required): The ID of the radio station - `currentSongId` (optional): The ID of the currently playing song for similarity analysis **Response:** ```json { "success": true, "message": "Recommended queue retrieved successfully", "data": [ { "id": "4iV5W9uYEdYUVa79Axb7Rh", "popularity": 85, "tempo": 120.5, "audioFeatures": { "danceability": 0.8, "energy": 0.7, "valence": 0.6, "acousticness": 0.1, "instrumentalness": 0.0, "speechiness": 0.04 } } ] } ``` ## Error Responses All error responses follow this format: ```json { "success": false, "message": "Error description", "data": null } ``` ## Usage Examples ### Creating a Station ```bash curl -X POST http://localhost:8080/api/radio-stations \ -H "Content-Type: application/json" \ -d '{"name": "My Station", "description": "Great music"}' ``` ### Joining a Station ```bash curl -X POST http://localhost:8080/api/clients/connect \ -H "Content-Type: application/json" \ -d '{"username": "john", "joinCode": "ABC123"}' ``` ### Getting All Stations (with authentication) ```bash curl -X GET "http://localhost:8080/api/radio-stations" \ -H "Authorization: Bearer {token}" ``` ### Deleting a Station (owner only) ```bash curl -X DELETE http://localhost:8080/api/radio-stations/{stationId} \ -H "Authorization: Bearer {ownerToken}" ``` ### Adding a Song to Client's Preferred Queue ```bash curl -X POST http://localhost:8080/api/songs/queue \ -H "Content-Type: application/json" \ -H "Authorization: Bearer {clientToken}" \ -d '{ "song": { "id": "4iV5W9uYEdYUVa79Axb7Rh", "popularity": 85, "tempo": 120.5, "danceability": 0.8, "energy": 0.7, "valence": 0.6, "acousticness": 0.1, "instrumentalness": 0.0, "liveness": 0.1, "speechiness": 0.04 }, "clientId": "client-uuid", "radioStationId": "station-uuid" }' ``` ### Getting Radio Station Queue ```bash curl -X GET "http://localhost:8080/api/songs/queue?radioStationId=station-uuid" \ -H "Authorization: Bearer {token}" ``` ## Frontend Integration Notes ### Merging Track and Audio Features The frontend can easily merge track information with audio features using JavaScript object spread: ```javascript // Track object from Spotify API const trackObj = { id: "4iV5W9uYEdYUVa79Axb7Rh", popularity: 85, tempo: 120.5, }; // Audio features object from Spotify API const audioFeaturesObj = { danceability: 0.8, energy: 0.7, valence: 0.6, acousticness: 0.1, instrumentalness: 0.0, liveness: 0.1, speechiness: 0.04, }; // Merge objects for API request const merged = { ...trackObj, ...audioFeaturesObj }; ``` ### Queue Data Structure The queue endpoints return/accept arrays of song objects. Each song object contains: - Basic track info (id, popularity, tempo) - Audio features (danceability, energy, valence, etc.) - All properties are at the root level (flattened structure)