2001 lines
40 KiB
Markdown
2001 lines
40 KiB
Markdown
# API Reference
|
|
|
|
Comprehensive API documentation for Sonic Cloud platform endpoints.
|
|
|
|
---
|
|
|
|
## Authentication Endpoints
|
|
|
|
API endpoints for user registration, login, and password recovery.
|
|
|
|
### POST /api/auth/register
|
|
**Description**: Register a new user account on the platform.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "securePassword123",
|
|
"username": "username",
|
|
"displayName": "Display Name" // Optional
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"user": {
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"username": "username",
|
|
"displayName": "Display Name",
|
|
"role": "USER"
|
|
},
|
|
"token": "jwt_token_string"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing required fields or invalid email format
|
|
- 409 Conflict: Email or username already exists
|
|
|
|
**Implementation**: `app/api/auth/register/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/auth/login
|
|
**Description**: Authenticate user credentials and receive a session token.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "securePassword123"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"user": {
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"username": "username",
|
|
"displayName": "Display Name",
|
|
"role": "USER"
|
|
},
|
|
"token": "jwt_token_string"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing email or password
|
|
- 401 Unauthorized: Invalid credentials
|
|
|
|
**Implementation**: `app/api/auth/login/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/auth/forgot-password
|
|
**Description**: Initiate password reset process by sending reset token via email.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"email": "user@example.com"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"message": "Password reset email sent"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing email
|
|
- 404 Not Found: User with email not found
|
|
|
|
**Implementation**: `app/api/auth/forgot-password/route.ts`
|
|
|
|
**Note**: Reset token is generated and stored with expiration timestamp. Token is sent via email (email service integration required).
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/auth/reset-password
|
|
**Description**: Reset user password using a valid reset token from email.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"token": "reset_token_from_email",
|
|
"newPassword": "newSecurePassword123"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"message": "Password reset successful"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing token or newPassword
|
|
- 401 Unauthorized: Invalid or expired token
|
|
- 404 Not Found: User not found
|
|
|
|
**Implementation**: `app/api/auth/reset-password/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## User Endpoints
|
|
|
|
API endpoints for managing user profile information.
|
|
|
|
### GET /api/users/me
|
|
**Description**: Retrieve the current authenticated user's profile information.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"username": "username",
|
|
"displayName": "Display Name",
|
|
"bio": "User biography text",
|
|
"avatarUrl": "https://example.com/avatar.jpg",
|
|
"websiteUrl": "https://example.com",
|
|
"role": "USER",
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name"
|
|
} // If user is an artist
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 404 Not Found: User not found
|
|
|
|
**Implementation**: `app/api/users/me/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/users/me
|
|
**Description**: Update the current authenticated user's profile information.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"displayName": "New Display Name",
|
|
"bio": "Updated biography",
|
|
"avatarUrl": "https://example.com/new-avatar.jpg",
|
|
"websiteUrl": "https://example.com"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"username": "username",
|
|
"displayName": "New Display Name",
|
|
"bio": "Updated biography",
|
|
"avatarUrl": "https://example.com/new-avatar.jpg",
|
|
"websiteUrl": "https://example.com",
|
|
"role": "USER"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 404 Not Found: User not found
|
|
|
|
**Implementation**: `app/api/users/me/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Artist Endpoints
|
|
|
|
API endpoints for managing artist profiles, songs, and albums.
|
|
|
|
### POST /api/artists
|
|
**Description**: Create a new artist profile for the authenticated user.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"name": "Artist Name",
|
|
"bio": "Artist biography",
|
|
"avatarUrl": "https://example.com/avatar.jpg",
|
|
"bannerUrl": "https://example.com/banner.jpg",
|
|
"websiteUrl": "https://example.com",
|
|
"spotifyUrl": "https://open.spotify.com/artist/...",
|
|
"instagramUrl": "https://instagram.com/artist"
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"userId": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"bio": "Artist biography",
|
|
"verified": false,
|
|
"createdAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing required fields or user already has artist profile
|
|
- 401 Unauthorized: Missing or invalid token
|
|
|
|
**Implementation**: `app/api/artists/route.ts`
|
|
|
|
**Note**: Slug is auto-generated from artist name for URL-friendly identifiers.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/artists/{id}
|
|
**Description**: Retrieve detailed information about a specific artist including statistics and relationships.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Artist UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"bio": "Artist biography",
|
|
"avatarUrl": "https://example.com/avatar.jpg",
|
|
"bannerUrl": "https://example.com/banner.jpg",
|
|
"verified": true,
|
|
"websiteUrl": "https://example.com",
|
|
"spotifyUrl": "https://open.spotify.com/artist/...",
|
|
"instagramUrl": "https://instagram.com/artist",
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"_count": {
|
|
"songs": 42,
|
|
"albums": 5
|
|
},
|
|
"label": {
|
|
"id": "uuid",
|
|
"name": "Label Name"
|
|
} // If artist is signed to label
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Artist not found
|
|
|
|
**Implementation**: `app/api/artists/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/artists/{id}
|
|
**Description**: Update artist profile information. Only the artist owner can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Artist UUID
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"name": "Updated Artist Name",
|
|
"bio": "Updated biography",
|
|
"avatarUrl": "https://example.com/new-avatar.jpg",
|
|
"bannerUrl": "https://example.com/new-banner.jpg",
|
|
"websiteUrl": "https://example.com",
|
|
"spotifyUrl": "https://open.spotify.com/artist/...",
|
|
"instagramUrl": "https://instagram.com/artist"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"name": "Updated Artist Name",
|
|
"slug": "updated-artist-name",
|
|
"bio": "Updated biography",
|
|
"verified": true
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the artist owner
|
|
- 404 Not Found: Artist not found
|
|
|
|
**Implementation**: `app/api/artists/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/artists/{id}/songs
|
|
**Description**: Retrieve all public songs by a specific artist.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Artist UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"playCount": 1234,
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"album": {
|
|
"id": "uuid",
|
|
"title": "Album Title"
|
|
},
|
|
"genres": [
|
|
{ "name": "Rock", "slug": "rock" }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Artist not found
|
|
|
|
**Implementation**: `app/api/artists/[id]/songs/route.ts`
|
|
|
|
**Note**: Only returns songs where `isPublic = true`.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/artists/{id}/albums
|
|
**Description**: Retrieve all albums by a specific artist, sorted by release date (newest first).
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Artist UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"releaseDate": "2025-01-01T00:00:00.000Z",
|
|
"albumType": "ALBUM", // or "EP", "SINGLE"
|
|
"_count": {
|
|
"songs": 12
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Artist not found
|
|
|
|
**Implementation**: `app/api/artists/[id]/albums/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Song Endpoints
|
|
|
|
API endpoints for uploading, managing, and tracking song playback.
|
|
|
|
### POST /api/songs/upload
|
|
**Description**: Upload a new song to the platform. Only users with artist profiles can upload songs.
|
|
|
|
**Authentication**: Required (JWT token, artist only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"title": "Song Title",
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"duration": 240, // in seconds
|
|
"albumId": "uuid", // Optional
|
|
"isPublic": true,
|
|
"genres": ["rock", "indie"] // Array of genre slugs
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"artistId": "uuid",
|
|
"title": "Song Title",
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"duration": 240,
|
|
"playCount": 0,
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing required fields
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not an artist
|
|
|
|
**Implementation**: `app/api/songs/upload/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/songs/{id}
|
|
**Description**: Retrieve detailed information about a specific song. Public songs are always accessible, private songs only accessible to owner.
|
|
|
|
**Authentication**: Optional (required for private songs)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Song UUID
|
|
|
|
**Request Headers** (optional for public songs):
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"duration": 240,
|
|
"playCount": 1234,
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"verified": true
|
|
},
|
|
"album": {
|
|
"id": "uuid",
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/album-cover.jpg"
|
|
},
|
|
"genres": [
|
|
{
|
|
"id": "uuid",
|
|
"name": "Rock",
|
|
"slug": "rock",
|
|
"color": "#FF0000"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 403 Forbidden: Song is private and user is not owner
|
|
- 404 Not Found: Song not found
|
|
|
|
**Implementation**: `app/api/songs/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/songs/{id}
|
|
**Description**: Update song information. Only the song owner (artist) can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Song UUID
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"title": "Updated Song Title",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"isPublic": false,
|
|
"albumId": "uuid",
|
|
"genres": ["rock", "pop"]
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Updated Song Title",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"isPublic": false,
|
|
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the song owner
|
|
- 404 Not Found: Song not found
|
|
|
|
**Implementation**: `app/api/songs/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### DELETE /api/songs/{id}
|
|
**Description**: Delete a song from the platform. Only the song owner (artist) can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Song UUID
|
|
|
|
**Response** (204 No Content)
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the song owner
|
|
- 404 Not Found: Song not found
|
|
|
|
**Implementation**: `app/api/songs/[id]/route.ts`
|
|
|
|
**Note**: Deleting a song also removes it from all playlists and deletes associated share links.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/songs/{id}/play
|
|
**Description**: Increment the play count for a song. Used for tracking song popularity.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Song UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"playCount": 1235
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Song not found
|
|
|
|
**Implementation**: `app/api/songs/[id]/play/route.ts`
|
|
|
|
**Note**: This endpoint is called each time a song starts playing. It's rate-limited per user to prevent abuse.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Album Endpoints
|
|
|
|
API endpoints for creating and managing music albums.
|
|
|
|
### POST /api/albums
|
|
**Description**: Create a new album. Only users with artist profiles can create albums.
|
|
|
|
**Authentication**: Required (JWT token, artist only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"releaseDate": "2025-01-01",
|
|
"albumType": "ALBUM", // or "EP", "SINGLE"
|
|
"description": "Album description text"
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"artistId": "uuid",
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"releaseDate": "2025-01-01T00:00:00.000Z",
|
|
"albumType": "ALBUM",
|
|
"description": "Album description text",
|
|
"createdAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing required fields
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not an artist
|
|
|
|
**Implementation**: `app/api/albums/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/albums/{id}
|
|
**Description**: Retrieve album details including all songs in the album.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Album UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"releaseDate": "2025-01-01T00:00:00.000Z",
|
|
"albumType": "ALBUM",
|
|
"description": "Album description text",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"verified": true
|
|
},
|
|
"songs": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"trackNumber": 1,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"playCount": 1234
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Album not found
|
|
|
|
**Implementation**: `app/api/albums/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/albums/{id}
|
|
**Description**: Update album information. Only the album owner (artist) can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Album UUID
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"title": "Updated Album Title",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"description": "Updated description",
|
|
"albumType": "EP"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Updated Album Title",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"description": "Updated description",
|
|
"albumType": "EP",
|
|
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the album owner
|
|
- 404 Not Found: Album not found
|
|
|
|
**Implementation**: `app/api/albums/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### DELETE /api/albums/{id}
|
|
**Description**: Delete an album from the platform. Only the album owner (artist) can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Album UUID
|
|
|
|
**Response** (204 No Content)
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the album owner
|
|
- 404 Not Found: Album not found
|
|
|
|
**Implementation**: `app/api/albums/[id]/route.ts`
|
|
|
|
**Note**: Deleting an album does NOT delete the songs in the album. Songs become album-less but remain on the platform.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Playlist Endpoints
|
|
|
|
API endpoints for creating and managing user playlists.
|
|
|
|
### GET /api/playlists
|
|
**Description**: Retrieve all playlists created by the authenticated user.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"title": "Playlist Title",
|
|
"description": "Playlist description",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"_count": {
|
|
"songs": 24
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
|
|
**Implementation**: `app/api/playlists/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/playlists
|
|
**Description**: Create a new playlist for the authenticated user.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"title": "Playlist Title",
|
|
"description": "Playlist description",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"isPublic": true
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"userId": "uuid",
|
|
"title": "Playlist Title",
|
|
"description": "Playlist description",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing title
|
|
- 401 Unauthorized: Missing or invalid token
|
|
|
|
**Implementation**: `app/api/playlists/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/playlists/{id}
|
|
**Description**: Retrieve playlist details with all songs. Public playlists are accessible to everyone, private playlists only to owner.
|
|
|
|
**Authentication**: Optional (required for private playlists)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Request Headers** (optional for public playlists):
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Playlist Title",
|
|
"description": "Playlist description",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"isPublic": true,
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"user": {
|
|
"id": "uuid",
|
|
"username": "username",
|
|
"displayName": "Display Name"
|
|
},
|
|
"songs": [
|
|
{
|
|
"id": "uuid",
|
|
"song": {
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name"
|
|
}
|
|
},
|
|
"position": 1,
|
|
"addedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 403 Forbidden: Playlist is private and user is not owner
|
|
- 404 Not Found: Playlist not found
|
|
|
|
**Implementation**: `app/api/playlists/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/playlists/{id}
|
|
**Description**: Update playlist information. Only the playlist owner can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"title": "Updated Playlist Title",
|
|
"description": "Updated description",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"isPublic": false
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"title": "Updated Playlist Title",
|
|
"description": "Updated description",
|
|
"coverUrl": "https://example.com/new-cover.jpg",
|
|
"isPublic": false,
|
|
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the playlist owner
|
|
- 404 Not Found: Playlist not found
|
|
|
|
**Implementation**: `app/api/playlists/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### DELETE /api/playlists/{id}
|
|
**Description**: Delete a playlist. Only the playlist owner can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Response** (204 No Content)
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the playlist owner
|
|
- 404 Not Found: Playlist not found
|
|
|
|
**Implementation**: `app/api/playlists/[id]/route.ts`
|
|
|
|
**Note**: Deleting a playlist does NOT delete the songs in it, only the playlist container.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/playlists/{id}/songs
|
|
**Description**: Add a song to a playlist. Only the playlist owner can add songs.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"songId": "uuid"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"playlistId": "uuid",
|
|
"songId": "uuid",
|
|
"position": 5,
|
|
"addedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing songId or song already in playlist
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the playlist owner
|
|
- 404 Not Found: Playlist or song not found
|
|
|
|
**Implementation**: `app/api/playlists/[id]/songs/route.ts`
|
|
|
|
**Note**: Position is automatically assigned as the last position in the playlist.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/playlists/{id}/reorder
|
|
**Description**: Reorder songs within a playlist. Only the playlist owner can reorder songs.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"songIds": ["uuid1", "uuid2", "uuid3"]
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"message": "Playlist reordered successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing songIds array or songIds don't match playlist
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the playlist owner
|
|
- 404 Not Found: Playlist not found
|
|
|
|
**Implementation**: `app/api/playlists/[id]/reorder/route.ts`
|
|
|
|
**Note**: All songs in the playlist must be included in the songIds array in the desired order.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Discovery Endpoints
|
|
|
|
API endpoints for discovering trending music, new releases, and browsing by genre.
|
|
|
|
### GET /api/discover/trending
|
|
**Description**: Retrieve trending public songs sorted by play count.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Query Parameters**:
|
|
- `limit` (number, optional): Number of results to return (default: 20, max: 100)
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"playCount": 5432,
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"verified": true
|
|
},
|
|
"genres": [
|
|
{ "name": "Rock", "slug": "rock", "color": "#FF0000" }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
**Implementation**: `app/api/discover/trending/route.ts`
|
|
|
|
**Note**: Only returns songs where `isPublic = true`, sorted by `playCount` descending.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/discover/new-releases
|
|
**Description**: Retrieve recently uploaded public songs sorted by creation date.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Query Parameters**:
|
|
- `limit` (number, optional): Number of results to return (default: 20, max: 100)
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"verified": true
|
|
},
|
|
"genres": [
|
|
{ "name": "Pop", "slug": "pop", "color": "#00FF00" }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
**Implementation**: `app/api/discover/new-releases/route.ts`
|
|
|
|
**Note**: Only returns songs where `isPublic = true`, sorted by `createdAt` descending.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/discover/genres
|
|
**Description**: Retrieve all available genres with song counts.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"name": "Rock",
|
|
"slug": "rock",
|
|
"description": "Rock music genre",
|
|
"color": "#FF0000",
|
|
"_count": {
|
|
"songs": 142
|
|
}
|
|
},
|
|
{
|
|
"id": "uuid",
|
|
"name": "Pop",
|
|
"slug": "pop",
|
|
"description": "Pop music genre",
|
|
"color": "#00FF00",
|
|
"_count": {
|
|
"songs": 98
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Implementation**: `app/api/discover/genres/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/discover/genres/{slug}
|
|
**Description**: Retrieve all public songs in a specific genre.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `slug` (string): Genre slug (e.g., "rock", "pop", "jazz")
|
|
|
|
**Query Parameters**:
|
|
- `limit` (number, optional): Number of results to return (default: 50, max: 100)
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"genre": {
|
|
"id": "uuid",
|
|
"name": "Rock",
|
|
"slug": "rock",
|
|
"description": "Rock music genre",
|
|
"color": "#FF0000"
|
|
},
|
|
"songs": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"playCount": 1234,
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"verified": true
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Genre not found
|
|
|
|
**Implementation**: `app/api/discover/genres/[slug]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Label Endpoints
|
|
|
|
API endpoints for managing record label profiles and artist rosters.
|
|
|
|
### POST /api/labels
|
|
**Description**: Create a new record label profile for the authenticated user.
|
|
|
|
**Authentication**: Required (JWT token)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"name": "Label Name",
|
|
"description": "Label description",
|
|
"logoUrl": "https://example.com/logo.png",
|
|
"websiteUrl": "https://example.com",
|
|
"contactEmail": "contact@label.com"
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"userId": "uuid",
|
|
"name": "Label Name",
|
|
"slug": "label-name",
|
|
"description": "Label description",
|
|
"logoUrl": "https://example.com/logo.png",
|
|
"websiteUrl": "https://example.com",
|
|
"contactEmail": "contact@label.com",
|
|
"createdAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing required fields or user already has label profile
|
|
- 401 Unauthorized: Missing or invalid token
|
|
|
|
**Implementation**: `app/api/labels/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/labels/{id}
|
|
**Description**: Retrieve label details with artist roster list.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Label UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"name": "Label Name",
|
|
"slug": "label-name",
|
|
"description": "Label description",
|
|
"logoUrl": "https://example.com/logo.png",
|
|
"websiteUrl": "https://example.com",
|
|
"contactEmail": "contact@label.com",
|
|
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
"artists": [
|
|
{
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"verified": true,
|
|
"avatarUrl": "https://example.com/avatar.jpg"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Label not found
|
|
|
|
**Implementation**: `app/api/labels/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PUT /api/labels/{id}
|
|
**Description**: Update label profile information. Only the label owner can perform this action.
|
|
|
|
**Authentication**: Required (JWT token, owner only)
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Request Headers**:
|
|
```
|
|
Authorization: Bearer jwt_token_string
|
|
```
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Label UUID
|
|
|
|
**Request Body** (all fields optional):
|
|
```json
|
|
{
|
|
"name": "Updated Label Name",
|
|
"description": "Updated description",
|
|
"logoUrl": "https://example.com/new-logo.png",
|
|
"websiteUrl": "https://example.com",
|
|
"contactEmail": "newcontact@label.com"
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"name": "Updated Label Name",
|
|
"slug": "updated-label-name",
|
|
"description": "Updated description",
|
|
"logoUrl": "https://example.com/new-logo.png",
|
|
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 401 Unauthorized: Missing or invalid token
|
|
- 403 Forbidden: User is not the label owner
|
|
- 404 Not Found: Label not found
|
|
|
|
**Implementation**: `app/api/labels/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/labels/{id}/stats
|
|
**Description**: Retrieve statistical information about a label including artist count, total songs, albums, and play counts.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Label UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"artistCount": 15,
|
|
"totalSongs": 342,
|
|
"totalAlbums": 48,
|
|
"totalPlays": 123456
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Label not found
|
|
|
|
**Implementation**: `app/api/labels/[id]/stats/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/labels/{id}/artists
|
|
**Description**: Retrieve all artists signed to a specific label.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Label UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"bio": "Artist biography",
|
|
"avatarUrl": "https://example.com/avatar.jpg",
|
|
"verified": true,
|
|
"_count": {
|
|
"songs": 24,
|
|
"albums": 3
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Label not found
|
|
|
|
**Implementation**: `app/api/labels/[id]/artists/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Search Endpoint
|
|
|
|
Full-text search across songs, artists, and albums.
|
|
|
|
### GET /api/search
|
|
**Description**: Search for songs, artists, and albums across the platform using full-text search.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**Query Parameters**:
|
|
- `q` (string, required): Search query text
|
|
- `type` (string, optional): Filter by type ("song", "artist", "album", or omit for all)
|
|
- `limit` (number, optional): Max results per type (default: 10, max: 50)
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"songs": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "Song Title",
|
|
"duration": 240,
|
|
"audioUrl": "https://example.com/audio.mp3",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"playCount": 1234,
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"verified": true
|
|
}
|
|
}
|
|
],
|
|
"artists": [
|
|
{
|
|
"id": "uuid",
|
|
"name": "Artist Name",
|
|
"slug": "artist-name",
|
|
"bio": "Artist biography",
|
|
"avatarUrl": "https://example.com/avatar.jpg",
|
|
"verified": true,
|
|
"_count": {
|
|
"songs": 24
|
|
}
|
|
}
|
|
],
|
|
"albums": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"releaseDate": "2025-01-01T00:00:00.000Z",
|
|
"albumType": "ALBUM",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name"
|
|
},
|
|
"_count": {
|
|
"songs": 12
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 400 Bad Request: Missing search query parameter
|
|
|
|
**Implementation**: `app/api/search/route.ts`
|
|
|
|
**Note**:
|
|
- Search is case-insensitive
|
|
- Only returns public songs (isPublic = true)
|
|
- Searches in song titles, artist names, album titles, and artist bios
|
|
- Results are relevance-sorted by database full-text search
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Sharing Endpoints
|
|
|
|
API endpoints for creating and tracking shareable links for content.
|
|
|
|
### POST /api/share/song/{id}
|
|
**Description**: Create a shareable link for a song that can be distributed on social media or messaging.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Song UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"token": "unique_share_token",
|
|
"url": "https://sonic-cloud.com/s/unique_share_token"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Song not found
|
|
|
|
**Implementation**: `app/api/share/song/[id]/route.ts`
|
|
|
|
**Note**: Share tokens are unique 10-character alphanumeric strings. Multiple share links can be created for the same song.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/share/playlist/{id}
|
|
**Description**: Create a shareable link for a playlist.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Playlist UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"token": "unique_share_token",
|
|
"url": "https://sonic-cloud.com/s/unique_share_token"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Playlist not found
|
|
- 403 Forbidden: Playlist is private
|
|
|
|
**Implementation**: `app/api/share/playlist/[id]/route.ts`
|
|
|
|
**Note**: Only public playlists can be shared.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/share/album/{id}
|
|
**Description**: Create a shareable link for an album.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `id` (string): Album UUID
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"token": "unique_share_token",
|
|
"url": "https://sonic-cloud.com/s/unique_share_token"
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Album not found
|
|
|
|
**Implementation**: `app/api/share/album/[id]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GET /api/share/{token}
|
|
**Description**: Resolve a share token and retrieve the shared content details.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `token` (string): Share token from shareable link
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"type": "SONG", // or "PLAYLIST", "ALBUM"
|
|
"targetId": "uuid",
|
|
"clickCount": 42,
|
|
"content": {
|
|
"id": "uuid",
|
|
"title": "Song/Playlist/Album Title",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"artist": {
|
|
"id": "uuid",
|
|
"name": "Artist Name"
|
|
}
|
|
// Additional fields based on type
|
|
}
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Share token not found or expired
|
|
|
|
**Implementation**: `app/api/share/[token]/route.ts`
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### POST /api/share/{token}/click
|
|
**Description**: Track when a share link is clicked. Used for analytics.
|
|
|
|
**Authentication**: Not required
|
|
|
|
<details>
|
|
<summary>🔧 Technical Details</summary>
|
|
|
|
**URL Parameters**:
|
|
- `token` (string): Share token
|
|
|
|
**Response** (200 OK):
|
|
```json
|
|
{
|
|
"clickCount": 43
|
|
}
|
|
```
|
|
|
|
**Error Responses**:
|
|
- 404 Not Found: Share token not found
|
|
|
|
**Implementation**: `app/api/share/[token]/click/route.ts`
|
|
|
|
**Note**: This endpoint is automatically called when a user opens a share link. It increments the click counter for analytics.
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Authentication & Authorization
|
|
|
|
### JWT Token Format
|
|
|
|
All authenticated endpoints require a JWT token in the Authorization header:
|
|
|
|
```
|
|
Authorization: Bearer <jwt_token>
|
|
```
|
|
|
|
Tokens are issued on successful login or registration and contain:
|
|
- User ID
|
|
- Email
|
|
- Role
|
|
- Expiration timestamp
|
|
|
|
### Token Expiration
|
|
|
|
JWT tokens expire after 7 days by default. After expiration, users must log in again to receive a new token.
|
|
|
|
### Permission Levels
|
|
|
|
| Role | Permissions |
|
|
|------|-------------|
|
|
| **USER** | Create playlists, like songs, follow artists |
|
|
| **ARTIST** | USER permissions + upload songs, create albums, manage artist profile |
|
|
| **LABEL** | USER permissions + manage label profile, invite artists |
|
|
| **ADMIN** | All permissions + verify artists, moderate content |
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
All API endpoints are subject to rate limiting to prevent abuse:
|
|
|
|
| Endpoint Type | Rate Limit |
|
|
|---------------|------------|
|
|
| Authentication | 5 requests per minute per IP |
|
|
| Song upload | 10 requests per hour per user |
|
|
| Play tracking | 1 request per song per user per minute |
|
|
| Search | 30 requests per minute per IP |
|
|
| General API | 100 requests per minute per user |
|
|
|
|
Rate limit headers are included in responses:
|
|
```
|
|
X-RateLimit-Limit: 100
|
|
X-RateLimit-Remaining: 95
|
|
X-RateLimit-Reset: 1609459200
|
|
```
|
|
|
|
---
|
|
|
|
## Error Response Format
|
|
|
|
All error responses follow a consistent format:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"message": "Human-readable error message",
|
|
"code": "ERROR_CODE",
|
|
"details": {
|
|
"field": "Additional context"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Common HTTP Status Codes
|
|
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| 200 | Success |
|
|
| 201 | Created |
|
|
| 204 | No Content (successful deletion) |
|
|
| 400 | Bad Request (invalid input) |
|
|
| 401 | Unauthorized (missing or invalid token) |
|
|
| 403 | Forbidden (insufficient permissions) |
|
|
| 404 | Not Found (resource doesn't exist) |
|
|
| 409 | Conflict (duplicate resource) |
|
|
| 429 | Too Many Requests (rate limit exceeded) |
|
|
| 500 | Internal Server Error |
|
|
|
|
---
|
|
|
|
## Data Types & Formats
|
|
|
|
### Date/Time Format
|
|
All timestamps use ISO 8601 format:
|
|
```
|
|
2025-01-01T00:00:00.000Z
|
|
```
|
|
|
|
### UUID Format
|
|
All entity IDs use UUID v4:
|
|
```
|
|
123e4567-e89b-12d3-a456-426614174000
|
|
```
|
|
|
|
### Duration Format
|
|
Song durations are in seconds (integer):
|
|
```json
|
|
{
|
|
"duration": 240 // 4 minutes
|
|
}
|
|
```
|
|
|
|
### URL Format
|
|
All URLs must be valid HTTPS URLs:
|
|
```
|
|
https://example.com/file.mp3
|
|
```
|
|
|
|
---
|
|
|
|
## API Versioning
|
|
|
|
Current API version: **v1**
|
|
|
|
The API is versioned in the URL path. Future versions will be released as:
|
|
```
|
|
/api/v2/...
|
|
```
|
|
|
|
Version 1 endpoints will be supported for at least 12 months after v2 release.
|
|
|
|
---
|
|
|
|
## SDK & Client Libraries
|
|
|
|
Official client libraries are in development for:
|
|
|
|
- JavaScript/TypeScript (Browser & Node.js)
|
|
- Python
|
|
- Swift (iOS)
|
|
- Kotlin (Android)
|
|
|
|
Community-maintained libraries may be available. Check the [GitHub repository](https://github.com/sonic-cloud) for updates.
|
|
|
|
---
|
|
|
|
## Support & Resources
|
|
|
|
- **API Status**: [status.sonic-cloud.com](https://status.sonic-cloud.com)
|
|
- **Documentation**: [docs.sonic-cloud.com](https://docs.sonic-cloud.com)
|
|
- **GitHub Issues**: [github.com/sonic-cloud/issues](https://github.com/sonic-cloud/issues)
|
|
- **Developer Discord**: [discord.gg/sonic-cloud](https://discord.gg/sonic-cloud)
|
|
|
|
---
|
|
|
|
**Last Updated**: December 18, 2025
|
|
**API Version**: v1.0.0
|