Skip to content

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:8080

Authentication

All protected routes require Bearer token:

http
Authorization: Bearer <JWT_TOKEN>

Token is obtained via:

  • POST /user/login - Email/password
  • POST /user/google - OAuth
  • POST /user/apple - OAuth

URL Identifier System

Entities (Artist Spaces, Projects, Tracks) support a tiered identifier system for clean, user-friendly URLs.

Identifier Types

TypeFormatExampleDescription
ObjectId24-char hex507f1f77bcf86cd799439011Legacy MongoDB _id, always works as fallback
ShortId6-char alphanumericxr7kq2Auto-generated on entity creation via nanoid
Slug3-30 char stringstudio-madridUser-customized, premium feature

Resolution Priority

When an :identifier param is received, the API resolves in this order:

  1. Slug — exact match on slug field
  2. ShortId — exact match on shortId field
  3. ObjectId — fallback to _id if 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        # Same

Resource Naming Conventions

ResourceEndpointHTTP Methods
Users/userGET, PUT
Artist Spaces/artistGET, POST, PUT, DELETE
Projects/projectGET, POST, PUT, DELETE
Tracks/trackGET, POST, PUT, DELETE
Files/fileGET, POST, DELETE
Comments/commentGET, POST, PUT, DELETE
Notifications/notificationGET, 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 file

Request/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

MethodEndpointDescription
POST/user/registerCreate account
POST/user/loginEmail/password login
POST/user/googleGoogle OAuth
POST/user/appleApple OAuth
POST/user/forgot-passwordReset request
POST/user/reset-passwordReset confirm

Artist Spaces

MethodEndpointDescription
GET/artistList user's spaces
POST/artistCreate space (multipart)
GET/artist/:idGet space details
PUT/artist/:idUpdate space (multipart)
DELETE/artist/:idDelete space

Projects

MethodEndpointDescription
GET/projectList user's projects
POST/projectCreate project
GET/project/:idGet project details
PUT/project/:idUpdate project
DELETE/project/:idDelete project
GET/project/artist/:artistIdProjects by artist

Tracks

MethodEndpointDescription
GET/trackList user's tracks
POST/trackCreate track
GET/track/:idGet track details
PUT/track/:idUpdate track
DELETE/track/:idDelete track
GET/track/project/:projectIdTracks by project

Files

MethodEndpointDescription
POST/file/upload/:trackIdUpload file (multipart)
GET/file/:idGet file details
DELETE/file/:idDelete file
PUT/file/:id/approveMark as approved

Comments

MethodEndpointDescription
GET/comment/track/:trackId/file/:fileIdGet comments
POST/comment/track/:trackId/file/:fileIdCreate comment
PUT/comment/:idUpdate comment
DELETE/comment/:idDelete comment
POST/comment/:id/responseReply to comment

Collaboration

MethodEndpointDescription
POST/collaboration/invite/spaceInvite to artist
POST/collaboration/invite/projectInvite to project
POST/collaboration/invite/trackInvite to track
DELETE/collaboration/:resourceType/:id/:userIdRemove collaborator
POST/collaboration/link/createCreate share link

Notifications

MethodEndpointDescription
GET/notificationGet user notifications
PUT/notification/:id/readMark as read
DELETE/notification/:idDelete notification

Query Parameters

Pagination

GET /artist?page=1&limit=20

Filtering

GET /track?status=approved
GET /comment?isResolved=false

Sorting

GET /project?sort=updatedAt&order=desc

Population

GET /track/:id?populate=files,collaborators

File 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 WebP
  • mediumUrl - 600×600 WebP
  • url - 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

EndpointLimit
Authentication5 req/min
File upload10 req/min
General API100 req/min

Headers returned:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1612345678

Versioning Strategy

  • Current version: v1
  • Breaking changes → new version (v2)
  • Deprecation notice → 6 months before removal
  • Version in URL path: /v1/artist

Ctrl-Audio Platform Documentation