API Design & Standards
REST API Conventions
Base URL Structure
Production: https://api.sonnance.com/v1
Development: https://api-dev.sonnance.com/v1
Local: http://localhost:8080Authentication
All protected routes require Bearer token:
http
Authorization: Bearer <JWT_TOKEN>Token is obtained via:
POST /user/login- Email/passwordPOST /user/google- OAuthPOST /user/apple- OAuth
URL Identifier System
Entities (Artist Spaces, Projects, Tracks) support a tiered identifier system for clean, user-friendly URLs.
Identifier Types
| Type | Format | Example | Description |
|---|---|---|---|
| ObjectId | 24-char hex | 507f1f77bcf86cd799439011 | Legacy MongoDB _id, always works as fallback |
| ShortId | 6-char alphanumeric | xr7kq2 | Auto-generated on entity creation via nanoid |
| Slug | 3-30 char string | studio-madrid | User-customized, premium feature |
Resolution Priority
When an :identifier param is received, the API resolves in this order:
- Slug — exact match on
slugfield - ShortId — exact match on
shortIdfield - ObjectId — fallback to
_idif valid ObjectId format
This ensures old links (ObjectId-based) continue working while new short URLs take priority.
Usage in Endpoints
All entity endpoints accept any identifier type:
GET /artist/:identifier # Works with ObjectId, shortId, or slug
GET /project/:identifier # Same
GET /track/:identifier # SameResource Naming Conventions
| Resource | Endpoint | HTTP Methods |
|---|---|---|
| Users | /user | GET, PUT |
| Artist Spaces | /artist | GET, POST, PUT, DELETE |
| Projects | /project | GET, POST, PUT, DELETE |
| Tracks | /track | GET, POST, PUT, DELETE |
| Files | /file | GET, POST, DELETE |
| Comments | /comment | GET, POST, PUT, DELETE |
| Notifications | /notification | GET, PUT, DELETE |
Nested Resources
GET /artist/:identifier/projects # Projects in artist space
GET /project/:identifier/tracks # Tracks in project
GET /track/:identifier/files # Files in track
GET /file/:fileId/comments # Comments on fileRequest/Response Formats
Success Response
json
{
"_id": "507f1f77bcf86cd799439011",
"name": "Summer Vibes",
"createdAt": "2026-02-05T18:00:00.000Z",
...entityFields
}List Response
json
[
{ "_id": "...", "name": "Track 1" },
{ "_id": "...", "name": "Track 2" }
]Error Response
json
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}Endpoint Reference
Authentication
| Method | Endpoint | Description |
|---|---|---|
| POST | /user/register | Create account |
| POST | /user/login | Email/password login |
| POST | /user/google | Google OAuth |
| POST | /user/apple | Apple OAuth |
| POST | /user/forgot-password | Reset request |
| POST | /user/reset-password | Reset confirm |
Artist Spaces
| Method | Endpoint | Description |
|---|---|---|
| GET | /artist | List user's spaces |
| POST | /artist | Create space (multipart) |
| GET | /artist/:id | Get space details |
| PUT | /artist/:id | Update space (multipart) |
| DELETE | /artist/:id | Delete space |
Projects
| Method | Endpoint | Description |
|---|---|---|
| GET | /project | List user's projects |
| POST | /project | Create project |
| GET | /project/:id | Get project details |
| PUT | /project/:id | Update project |
| DELETE | /project/:id | Delete project |
| GET | /project/artist/:artistId | Projects by artist |
Tracks
| Method | Endpoint | Description |
|---|---|---|
| GET | /track | List user's tracks |
| POST | /track | Create track |
| GET | /track/:id | Get track details |
| PUT | /track/:id | Update track |
| DELETE | /track/:id | Delete track |
| GET | /track/project/:projectId | Tracks by project |
Files
| Method | Endpoint | Description |
|---|---|---|
| POST | /file/upload/:trackId | Upload file (multipart) |
| GET | /file/:id | Get file details |
| DELETE | /file/:id | Delete file |
| PUT | /file/:id/approve | Mark as approved |
Comments
| Method | Endpoint | Description |
|---|---|---|
| GET | /comment/track/:trackId/file/:fileId | Get comments |
| POST | /comment/track/:trackId/file/:fileId | Create comment |
| PUT | /comment/:id | Update comment |
| DELETE | /comment/:id | Delete comment |
| POST | /comment/:id/response | Reply to comment |
Collaboration
| Method | Endpoint | Description |
|---|---|---|
| POST | /collaboration/invite/space | Invite to artist |
| POST | /collaboration/invite/project | Invite to project |
| POST | /collaboration/invite/track | Invite to track |
| DELETE | /collaboration/:resourceType/:id/:userId | Remove collaborator |
| POST | /collaboration/link/create | Create share link |
Notifications
| Method | Endpoint | Description |
|---|---|---|
| GET | /notification | Get user notifications |
| PUT | /notification/:id/read | Mark as read |
| DELETE | /notification/:id | Delete notification |
Query Parameters
Pagination
GET /artist?page=1&limit=20Filtering
GET /track?status=approved
GET /comment?isResolved=falseSorting
GET /project?sort=updatedAt&order=descPopulation
GET /track/:id?populate=files,collaboratorsFile Upload
Multipart Form Data
http
POST /artist HTTP/1.1
Content-Type: multipart/form-data
name: "New Artist"
image: [binary file data]Image Variants (Auto-generated)
When uploading images, the API automatically creates:
thumbnailUrl- 150×150 WebPmediumUrl- 600×600 WebPurl- Original optimized WebP
All URLs point to CDN: https://sonnance-images-*.azurefd.net/...
WebSocket Events
Connection
typescript
const socket = io('wss://api.sonnance.com', {
auth: { token: 'JWT_TOKEN' }
});Room Management
typescript
// Join rooms
socket.emit('join:track', { trackId });
socket.emit('join:project', { projectId });
// Leave rooms
socket.emit('leave:track', { trackId });Event Subscriptions
typescript
// Incoming events
socket.on('comment:new', (data) => { ... });
socket.on('notification:new', (data) => { ... });
socket.on('collaborator:online', (data) => { ... });Rate Limiting
| Endpoint | Limit |
|---|---|
| Authentication | 5 req/min |
| File upload | 10 req/min |
| General API | 100 req/min |
Headers returned:
http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1612345678Versioning Strategy
- Current version:
v1 - Breaking changes → new version (
v2) - Deprecation notice → 6 months before removal
- Version in URL path:
/v1/artist