2093 lines
42 KiB
Markdown
2093 lines
42 KiB
Markdown
|
|
# ORIGIN_API_SPECIFICATION.md
|
||
|
|
|
||
|
|
## 📋 RÉSUMÉ EXÉCUTIF
|
||
|
|
|
||
|
|
Ce document définit la spécification complète et définitive de toutes les APIs de la plateforme Veza. Il documente 500+ endpoints REST, 50+ événements WebSocket, et 20+ services gRPC avec leurs schémas de requête/réponse, codes d'erreur standardisés, authentication flows, rate limiting, et versioning. L'API suit les principes REST/RESTful, utilise JSON comme format d'échange, et implémente OAuth 2.0 + JWT pour l'authentification.
|
||
|
|
|
||
|
|
## 🎯 OBJECTIFS
|
||
|
|
|
||
|
|
### Objectif Principal
|
||
|
|
Définir une API complète, cohérente, documentée, et immuable qui servira de contrat entre frontend/backend/mobile pendant 24 mois sans breaking changes.
|
||
|
|
|
||
|
|
### Objectifs Secondaires
|
||
|
|
- Assurer la cohérence des schémas (naming, structure, types)
|
||
|
|
- Standardiser les codes d'erreur et messages
|
||
|
|
- Faciliter l'intégration (clients, partenaires, développeurs tiers)
|
||
|
|
- Garantir la scalabilité (rate limiting, caching, pagination)
|
||
|
|
- Supporter le versioning (v1 stable, v2 pour évolutions)
|
||
|
|
|
||
|
|
## 📖 TABLE DES MATIÈRES
|
||
|
|
|
||
|
|
1. [Design Principles](#1-design-principles)
|
||
|
|
2. [Authentication & Authorization](#2-authentication--authorization)
|
||
|
|
3. [Common Patterns](#3-common-patterns)
|
||
|
|
4. [Error Handling](#4-error-handling)
|
||
|
|
5. [Rate Limiting](#5-rate-limiting)
|
||
|
|
6. [Versioning](#6-versioning)
|
||
|
|
7. [REST API Endpoints](#7-rest-api-endpoints)
|
||
|
|
8. [WebSocket APIs](#8-websocket-apis)
|
||
|
|
9. [gRPC APIs](#9-grpc-apis)
|
||
|
|
10. [OpenAPI 3.0 Specification](#10-openapi-30-specification)
|
||
|
|
|
||
|
|
## 🔒 RÈGLES IMMUABLES
|
||
|
|
|
||
|
|
1. **URLs DOIVENT suivre le pattern** `/api/v{version}/{resource}`
|
||
|
|
2. **HTTP methods DOIVENT respecter REST** (GET=read, POST=create, PUT=replace, PATCH=update, DELETE=delete)
|
||
|
|
3. **Responses DOIVENT être JSON** avec `Content-Type: application/json`
|
||
|
|
4. **Dates DOIVENT être ISO 8601** (format: `2025-11-02T14:30:00Z`)
|
||
|
|
5. **IDs DOIVENT être UUID v4** (format: `550e8400-e29b-41d4-a716-446655440000`)
|
||
|
|
6. **Pagination OBLIGATOIRE** pour collections (cursor-based par défaut)
|
||
|
|
7. **Rate limiting OBLIGATOIRE** (headers: `X-RateLimit-*`)
|
||
|
|
8. **Authentication JWT** dans header `Authorization: Bearer {token}`
|
||
|
|
9. **Error codes STANDARDISÉS** (range 1000-9999, voir section 4)
|
||
|
|
10. **Breaking changes INTERDITS** dans v1 (créer v2 si nécessaire)
|
||
|
|
|
||
|
|
## 1. DESIGN PRINCIPLES
|
||
|
|
|
||
|
|
### 1.1 RESTful Architecture
|
||
|
|
|
||
|
|
**Resource-Oriented URLs**:
|
||
|
|
```
|
||
|
|
✅ Good: GET /api/v1/tracks/{id}
|
||
|
|
❌ Bad: GET /api/v1/getTrackById?id={id}
|
||
|
|
|
||
|
|
✅ Good: POST /api/v1/tracks/{id}/like
|
||
|
|
❌ Bad: POST /api/v1/likeTrack
|
||
|
|
|
||
|
|
✅ Good: GET /api/v1/users/{id}/tracks
|
||
|
|
❌ Bad: GET /api/v1/getTracksForUser?userId={id}
|
||
|
|
```
|
||
|
|
|
||
|
|
**HTTP Method Semantics**:
|
||
|
|
```
|
||
|
|
GET - Retrieve resource(s) (idempotent, cacheable)
|
||
|
|
POST - Create new resource (non-idempotent)
|
||
|
|
PUT - Replace entire resource (idempotent)
|
||
|
|
PATCH - Partial update resource (idempotent)
|
||
|
|
DELETE - Delete resource (idempotent)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.2 Consistency
|
||
|
|
|
||
|
|
**Naming Conventions**:
|
||
|
|
- **Resources**: Plural nouns (`tracks`, `users`, `playlists`)
|
||
|
|
- **Fields**: snake_case (`created_at`, `user_id`, `is_active`)
|
||
|
|
- **Enums**: lowercase with underscores (`public`, `unlisted`, `private`)
|
||
|
|
|
||
|
|
**Common Fields**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "uuid",
|
||
|
|
"created_at": "ISO 8601 timestamp",
|
||
|
|
"updated_at": "ISO 8601 timestamp",
|
||
|
|
"deleted_at": "ISO 8601 timestamp | null"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.3 HATEOAS (Optional)
|
||
|
|
|
||
|
|
**Include links for navigation**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"title": "My Track",
|
||
|
|
"_links": {
|
||
|
|
"self": "/api/v1/tracks/550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"creator": "/api/v1/users/123e4567-e89b-12d3-a456-426614174000",
|
||
|
|
"likes": "/api/v1/tracks/550e8400-e29b-41d4-a716-446655440000/likes"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 2. AUTHENTICATION & AUTHORIZATION
|
||
|
|
|
||
|
|
### 2.1 JWT Authentication
|
||
|
|
|
||
|
|
**Login Flow**:
|
||
|
|
```
|
||
|
|
POST /api/v1/auth/login
|
||
|
|
Request:
|
||
|
|
{
|
||
|
|
"email": "user@example.com",
|
||
|
|
"password": "SecurePass123!"
|
||
|
|
}
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
|
|
"refresh_token": "dGhpc2lzYXJlZnJlc2h0b2tlbg...",
|
||
|
|
"expires_in": 900,
|
||
|
|
"token_type": "Bearer",
|
||
|
|
"user": {
|
||
|
|
"id": "uuid",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "johndoe",
|
||
|
|
"role": "user"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**JWT Claims**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sub": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"role": "user",
|
||
|
|
"token_version": 0,
|
||
|
|
"iat": 1730556000,
|
||
|
|
"exp": 1730559600
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Using Access Token**:
|
||
|
|
```
|
||
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
|
|
```
|
||
|
|
|
||
|
|
**Refresh Token Flow**:
|
||
|
|
```
|
||
|
|
POST /api/v1/auth/refresh
|
||
|
|
Request:
|
||
|
|
{
|
||
|
|
"refresh_token": "dGhpc2lzYXJlZnJlc2h0b2tlbg..."
|
||
|
|
}
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"access_token": "new_jwt_token...",
|
||
|
|
"expires_in": 900
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 OAuth 2.0 (Social Login)
|
||
|
|
|
||
|
|
**Supported Providers**: Google, GitHub, Discord, Spotify
|
||
|
|
|
||
|
|
**OAuth Flow**:
|
||
|
|
```
|
||
|
|
1. GET /api/v1/auth/oauth/{provider}
|
||
|
|
→ Redirect to provider authorization URL
|
||
|
|
|
||
|
|
2. Provider redirects back to: /api/v1/auth/oauth/{provider}/callback?code=...
|
||
|
|
|
||
|
|
3. Backend exchanges code for tokens and returns JWT
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 Authorization (RBAC)
|
||
|
|
|
||
|
|
**Roles**:
|
||
|
|
- `user` - Standard user (default)
|
||
|
|
- `creator` - Content creator (verified)
|
||
|
|
- `premium` - Premium subscriber
|
||
|
|
- `moderator` - Community moderator
|
||
|
|
- `admin` - System administrator
|
||
|
|
|
||
|
|
**Permission Matrix** (examples):
|
||
|
|
| Action | user | creator | premium | moderator | admin |
|
||
|
|
|--------|------|---------|---------|-----------|-------|
|
||
|
|
| Upload track | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||
|
|
| Delete own track | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||
|
|
| Delete any track | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||
|
|
| Create playlist | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||
|
|
| Ban user | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||
|
|
| Modify system config | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||
|
|
|
||
|
|
**Checking Permissions** (backend):
|
||
|
|
```go
|
||
|
|
// Middleware example
|
||
|
|
func RequireRole(allowedRoles ...string) gin.HandlerFunc {
|
||
|
|
return func(c *gin.Context) {
|
||
|
|
user := GetCurrentUser(c)
|
||
|
|
if !contains(allowedRoles, user.Role) {
|
||
|
|
c.JSON(403, ErrorResponse{Code: 1003, Message: "Forbidden"})
|
||
|
|
c.Abort()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
c.Next()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Usage
|
||
|
|
r.POST("/tracks", RequireRole("creator", "premium"), handlers.CreateTrack)
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3. COMMON PATTERNS
|
||
|
|
|
||
|
|
### 3.1 Pagination
|
||
|
|
|
||
|
|
**Cursor-Based Pagination** (recommended for feeds):
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks?limit=20&cursor=eyJpZCI6IjU1MGU4NDAwIn0
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"data": [ /* 20 tracks */ ],
|
||
|
|
"pagination": {
|
||
|
|
"next_cursor": "eyJpZCI6IjY2MWU5NTExIn0",
|
||
|
|
"has_more": true,
|
||
|
|
"limit": 20
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Offset-Based Pagination** (for fixed pages):
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks?page=2&per_page=20
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"data": [ /* 20 tracks */ ],
|
||
|
|
"pagination": {
|
||
|
|
"current_page": 2,
|
||
|
|
"per_page": 20,
|
||
|
|
"total_pages": 150,
|
||
|
|
"total_count": 3000
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 Filtering
|
||
|
|
|
||
|
|
**Query Parameters**:
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks?genre=electronic&bpm_min=120&bpm_max=140&visibility=public
|
||
|
|
|
||
|
|
Supported operators:
|
||
|
|
- Equality: ?genre=electronic
|
||
|
|
- Range: ?bpm_min=120&bpm_max=140
|
||
|
|
- In: ?genre=electronic,house,techno
|
||
|
|
- Date range: ?created_after=2025-01-01&created_before=2025-12-31
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.3 Sorting
|
||
|
|
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks?sort=-created_at,title
|
||
|
|
|
||
|
|
Format:
|
||
|
|
- {field} for ascending
|
||
|
|
- -{field} for descending
|
||
|
|
- Multiple fields: comma-separated
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.4 Field Selection (Sparse Fieldsets)
|
||
|
|
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks?fields=id,title,artist,duration
|
||
|
|
|
||
|
|
Response includes only requested fields (reduces payload size)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.5 Embedding Related Resources
|
||
|
|
|
||
|
|
```
|
||
|
|
GET /api/v1/tracks/{id}?include=creator,likes
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"id": "uuid",
|
||
|
|
"title": "Track Title",
|
||
|
|
"creator": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "johndoe",
|
||
|
|
"avatar_url": "https://..."
|
||
|
|
},
|
||
|
|
"likes": [
|
||
|
|
{ "user_id": "uuid", "created_at": "2025-11-01T12:00:00Z" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.6 Bulk Operations
|
||
|
|
|
||
|
|
**Batch Create**:
|
||
|
|
```
|
||
|
|
POST /api/v1/tracks/batch
|
||
|
|
Request:
|
||
|
|
{
|
||
|
|
"tracks": [
|
||
|
|
{ "title": "Track 1", "file_id": "uuid1" },
|
||
|
|
{ "title": "Track 2", "file_id": "uuid2" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
Response:
|
||
|
|
{
|
||
|
|
"created": [
|
||
|
|
{ "id": "uuid", "title": "Track 1" },
|
||
|
|
{ "id": "uuid", "title": "Track 2" }
|
||
|
|
],
|
||
|
|
"failed": []
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Batch Update**:
|
||
|
|
```
|
||
|
|
PATCH /api/v1/tracks/batch
|
||
|
|
Request:
|
||
|
|
{
|
||
|
|
"updates": [
|
||
|
|
{ "id": "uuid1", "visibility": "private" },
|
||
|
|
{ "id": "uuid2", "title": "New Title" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4. ERROR HANDLING
|
||
|
|
|
||
|
|
### 4.1 Error Response Format
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"error": {
|
||
|
|
"code": 1001,
|
||
|
|
"message": "Validation failed",
|
||
|
|
"details": [
|
||
|
|
{
|
||
|
|
"field": "email",
|
||
|
|
"message": "Invalid email format"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"timestamp": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 HTTP Status Codes
|
||
|
|
|
||
|
|
| Status | Usage |
|
||
|
|
|--------|-------|
|
||
|
|
| **200 OK** | Successful GET, PATCH, PUT |
|
||
|
|
| **201 Created** | Successful POST (resource created) |
|
||
|
|
| **204 No Content** | Successful DELETE |
|
||
|
|
| **400 Bad Request** | Invalid request (validation errors) |
|
||
|
|
| **401 Unauthorized** | Missing or invalid authentication |
|
||
|
|
| **403 Forbidden** | Authenticated but insufficient permissions |
|
||
|
|
| **404 Not Found** | Resource not found |
|
||
|
|
| **409 Conflict** | Resource conflict (duplicate, state) |
|
||
|
|
| **422 Unprocessable Entity** | Semantic errors |
|
||
|
|
| **429 Too Many Requests** | Rate limit exceeded |
|
||
|
|
| **500 Internal Server Error** | Server error |
|
||
|
|
| **503 Service Unavailable** | Temporary unavailable |
|
||
|
|
|
||
|
|
### 4.3 Error Codes (1000-9999)
|
||
|
|
|
||
|
|
**Authentication & Authorization (1000-1999)**:
|
||
|
|
```
|
||
|
|
1000 - Invalid credentials
|
||
|
|
1001 - Token expired
|
||
|
|
1002 - Token invalid
|
||
|
|
1003 - Insufficient permissions
|
||
|
|
1004 - Account not verified
|
||
|
|
1005 - Account suspended
|
||
|
|
1006 - Account banned
|
||
|
|
1007 - Two-factor authentication required
|
||
|
|
1008 - Invalid two-factor code
|
||
|
|
1009 - OAuth provider error
|
||
|
|
```
|
||
|
|
|
||
|
|
**Validation Errors (2000-2999)**:
|
||
|
|
```
|
||
|
|
2000 - Validation failed (generic)
|
||
|
|
2001 - Required field missing
|
||
|
|
2002 - Invalid field format
|
||
|
|
2003 - Field value out of range
|
||
|
|
2004 - Invalid enum value
|
||
|
|
2005 - Invalid UUID format
|
||
|
|
2006 - Invalid date format
|
||
|
|
2007 - Invalid email format
|
||
|
|
2008 - Invalid URL format
|
||
|
|
2009 - File too large
|
||
|
|
2010 - Unsupported file type
|
||
|
|
```
|
||
|
|
|
||
|
|
**Resource Errors (3000-3999)**:
|
||
|
|
```
|
||
|
|
3000 - Resource not found
|
||
|
|
3001 - Resource already exists
|
||
|
|
3002 - Resource conflict
|
||
|
|
3003 - Resource deleted
|
||
|
|
3004 - Resource locked
|
||
|
|
3005 - Resource quota exceeded
|
||
|
|
```
|
||
|
|
|
||
|
|
**Business Logic Errors (4000-4999)**:
|
||
|
|
```
|
||
|
|
4000 - Operation not allowed
|
||
|
|
4001 - Insufficient balance
|
||
|
|
4002 - Product out of stock
|
||
|
|
4003 - Order already paid
|
||
|
|
4004 - Cannot cancel order
|
||
|
|
4005 - Maximum upload limit reached
|
||
|
|
4006 - Duplicate track title
|
||
|
|
4007 - Playlist is full
|
||
|
|
4008 - Cannot unfollow yourself
|
||
|
|
4009 - Already following user
|
||
|
|
4010 - User blocked you
|
||
|
|
```
|
||
|
|
|
||
|
|
**Rate Limiting (5000-5099)**:
|
||
|
|
```
|
||
|
|
5000 - Rate limit exceeded
|
||
|
|
5001 - Daily quota exceeded
|
||
|
|
5002 - Monthly quota exceeded
|
||
|
|
5003 - Concurrent request limit
|
||
|
|
```
|
||
|
|
|
||
|
|
**External Services (6000-6999)**:
|
||
|
|
```
|
||
|
|
6000 - Payment provider error
|
||
|
|
6001 - File storage error
|
||
|
|
6002 - Email service error
|
||
|
|
6003 - SMS service error
|
||
|
|
6004 - CDN error
|
||
|
|
6005 - Search service error
|
||
|
|
```
|
||
|
|
|
||
|
|
**Internal Errors (9000-9999)**:
|
||
|
|
```
|
||
|
|
9000 - Internal server error
|
||
|
|
9001 - Database error
|
||
|
|
9002 - Cache error
|
||
|
|
9003 - Message queue error
|
||
|
|
9004 - Configuration error
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5. RATE LIMITING
|
||
|
|
|
||
|
|
### 5.1 Rate Limits by Endpoint Type
|
||
|
|
|
||
|
|
| Endpoint Type | Limit | Window |
|
||
|
|
|---------------|-------|--------|
|
||
|
|
| **Authentication** | 10 requests | 1 minute |
|
||
|
|
| **Read (GET)** | 1000 requests | 1 hour |
|
||
|
|
| **Write (POST/PUT/PATCH)** | 100 requests | 1 hour |
|
||
|
|
| **File Upload** | 10 uploads | 1 hour |
|
||
|
|
| **Search** | 500 requests | 1 hour |
|
||
|
|
| **Streaming** | 10,000 plays | 1 day |
|
||
|
|
|
||
|
|
### 5.2 Rate Limit Headers
|
||
|
|
|
||
|
|
**Included in every response**:
|
||
|
|
```
|
||
|
|
X-RateLimit-Limit: 1000
|
||
|
|
X-RateLimit-Remaining: 950
|
||
|
|
X-RateLimit-Reset: 1730559600
|
||
|
|
X-RateLimit-Window: 3600
|
||
|
|
```
|
||
|
|
|
||
|
|
**When rate limit exceeded (429)**:
|
||
|
|
```
|
||
|
|
HTTP/1.1 429 Too Many Requests
|
||
|
|
X-RateLimit-Limit: 1000
|
||
|
|
X-RateLimit-Remaining: 0
|
||
|
|
X-RateLimit-Reset: 1730559600
|
||
|
|
Retry-After: 1800
|
||
|
|
|
||
|
|
{
|
||
|
|
"error": {
|
||
|
|
"code": 5000,
|
||
|
|
"message": "Rate limit exceeded. Try again in 30 minutes."
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5.3 Premium User Limits
|
||
|
|
|
||
|
|
| Endpoint Type | Standard | Premium | Factor |
|
||
|
|
|---------------|----------|---------|--------|
|
||
|
|
| Read | 1,000/hr | 5,000/hr | 5x |
|
||
|
|
| Write | 100/hr | 500/hr | 5x |
|
||
|
|
| Upload | 10/hr | 50/hr | 5x |
|
||
|
|
| Search | 500/hr | 2,500/hr | 5x |
|
||
|
|
|
||
|
|
## 6. VERSIONING
|
||
|
|
|
||
|
|
### 6.1 URL Versioning
|
||
|
|
|
||
|
|
**Current version**: v1
|
||
|
|
**Format**: `/api/v{major_version}/{resource}`
|
||
|
|
|
||
|
|
```
|
||
|
|
/api/v1/tracks
|
||
|
|
/api/v2/tracks (future)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6.2 Version Lifecycle
|
||
|
|
|
||
|
|
| Version | Status | Support End |
|
||
|
|
|---------|--------|-------------|
|
||
|
|
| **v1** | ✅ Stable | Q4 2026 minimum |
|
||
|
|
| **v2** | 🔄 Planned | TBD |
|
||
|
|
|
||
|
|
### 6.3 Breaking vs Non-Breaking Changes
|
||
|
|
|
||
|
|
**Non-Breaking (allowed in v1)**:
|
||
|
|
- Adding new endpoints
|
||
|
|
- Adding optional query parameters
|
||
|
|
- Adding new fields to responses (clients should ignore unknown fields)
|
||
|
|
- Adding new enum values (if gracefully handled)
|
||
|
|
- Adding new error codes
|
||
|
|
|
||
|
|
**Breaking (require v2)**:
|
||
|
|
- Removing endpoints
|
||
|
|
- Removing fields from responses
|
||
|
|
- Changing field types
|
||
|
|
- Changing required/optional status of fields
|
||
|
|
- Changing URL structure
|
||
|
|
- Changing authentication method
|
||
|
|
|
||
|
|
### 6.4 Deprecation Process
|
||
|
|
|
||
|
|
1. **Announce** deprecation (6 months notice minimum)
|
||
|
|
2. **Add header** `Deprecation: true` to deprecated endpoints
|
||
|
|
3. **Provide migration guide** in docs
|
||
|
|
4. **Monitor usage** of deprecated endpoints
|
||
|
|
5. **Remove** in next major version
|
||
|
|
|
||
|
|
## 7. REST API ENDPOINTS
|
||
|
|
|
||
|
|
### 7.1 Module: Authentication
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/register`
|
||
|
|
**Description**: Register new user account.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "johndoe",
|
||
|
|
"password": "SecurePass123!",
|
||
|
|
"first_name": "John",
|
||
|
|
"last_name": "Doe"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"user": {
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "johndoe",
|
||
|
|
"role": "user",
|
||
|
|
"is_active": true,
|
||
|
|
"created_at": "2025-11-02T14:30:00Z"
|
||
|
|
},
|
||
|
|
"message": "Registration successful. Please verify your email."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `400` - Validation failed (2000)
|
||
|
|
- `409` - Email/username already exists (3001)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/login`
|
||
|
|
**Description**: Login with email/password.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"email": "user@example.com",
|
||
|
|
"password": "SecurePass123!"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
|
|
"refresh_token": "dGhpc2lzYXJlZnJlc2h0b2tlbg...",
|
||
|
|
"expires_in": 900,
|
||
|
|
"token_type": "Bearer",
|
||
|
|
"user": {
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "johndoe",
|
||
|
|
"role": "creator"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `400` - Invalid credentials (1000)
|
||
|
|
- `403` - Account suspended (1005)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/logout`
|
||
|
|
**Description**: Logout (invalidate refresh token).
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Request**: Empty
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/refresh`
|
||
|
|
**Description**: Refresh access token.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"refresh_token": "dGhpc2lzYXJlZnJlc2h0b2tlbg..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"access_token": "new_jwt_token...",
|
||
|
|
"expires_in": 900
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `401` - Invalid refresh token (1002)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/forgot-password`
|
||
|
|
**Description**: Request password reset email.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"email": "user@example.com"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"message": "Password reset email sent if account exists."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/reset-password`
|
||
|
|
**Description**: Reset password with token.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"token": "reset_token_from_email",
|
||
|
|
"new_password": "NewSecurePass456!"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"message": "Password reset successful."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `400` - Invalid or expired token (1002)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/auth/verify-email`
|
||
|
|
**Description**: Verify email with token.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"token": "email_verification_token"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"message": "Email verified successfully."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/auth/me`
|
||
|
|
**Description**: Get current authenticated user.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "johndoe",
|
||
|
|
"role": "creator",
|
||
|
|
"is_active": true,
|
||
|
|
"is_verified": true,
|
||
|
|
"profile": {
|
||
|
|
"bio": "Music producer from NYC",
|
||
|
|
"avatar_url": "https://cdn.veza.io/avatars/...",
|
||
|
|
"follower_count": 1250,
|
||
|
|
"following_count": 450
|
||
|
|
},
|
||
|
|
"created_at": "2024-01-15T10:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `401` - Unauthorized (1002)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.2 Module: Users
|
||
|
|
|
||
|
|
#### `GET /api/v1/users/{id}`
|
||
|
|
**Description**: Get user profile by ID.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `id` (path, required) - User UUID
|
||
|
|
- `include` (query, optional) - Related resources (`profile,stats,badges`)
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"username": "johndoe",
|
||
|
|
"display_name": "John Doe",
|
||
|
|
"role": "creator",
|
||
|
|
"profile": {
|
||
|
|
"bio": "Music producer from NYC",
|
||
|
|
"avatar_url": "https://cdn.veza.io/avatars/...",
|
||
|
|
"banner_url": "https://cdn.veza.io/banners/...",
|
||
|
|
"location": "New York, USA",
|
||
|
|
"website_url": "https://johndoe.com"
|
||
|
|
},
|
||
|
|
"stats": {
|
||
|
|
"follower_count": 1250,
|
||
|
|
"following_count": 450,
|
||
|
|
"track_count": 85,
|
||
|
|
"playlist_count": 12
|
||
|
|
},
|
||
|
|
"badges": [
|
||
|
|
{
|
||
|
|
"name": "Verified Creator",
|
||
|
|
"icon_url": "https://cdn.veza.io/badges/verified.svg",
|
||
|
|
"rarity": "rare"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"created_at": "2024-01-15T10:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `404` - User not found (3000)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `PATCH /api/v1/users/{id}`
|
||
|
|
**Description**: Update user profile.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Permissions**: Own profile or admin
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"display_name": "Johnny Doe",
|
||
|
|
"profile": {
|
||
|
|
"bio": "Award-winning music producer",
|
||
|
|
"location": "Los Angeles, USA",
|
||
|
|
"website_url": "https://johnnydoe.com"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK): Same as GET
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `403` - Forbidden (1003)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/users/{id}/tracks`
|
||
|
|
**Description**: Get user's tracks.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `id` (path, required) - User UUID
|
||
|
|
- `limit` (query, optional, default=20) - Page size
|
||
|
|
- `cursor` (query, optional) - Pagination cursor
|
||
|
|
- `sort` (query, optional, default=-created_at) - Sort field
|
||
|
|
- `visibility` (query, optional) - Filter by visibility
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "track-uuid",
|
||
|
|
"title": "Summer Vibes",
|
||
|
|
"artist": "johndoe",
|
||
|
|
"duration": 245,
|
||
|
|
"genre": "Electronic",
|
||
|
|
"cover_art_url": "https://...",
|
||
|
|
"play_count": 12500,
|
||
|
|
"like_count": 850,
|
||
|
|
"created_at": "2025-06-15T10:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": {
|
||
|
|
"next_cursor": "eyJpZCI6IjY2MWU5NTExIn0",
|
||
|
|
"has_more": true,
|
||
|
|
"limit": 20
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/users/{id}/followers`
|
||
|
|
**Description**: Get user's followers.
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "follower-uuid",
|
||
|
|
"username": "jane_smith",
|
||
|
|
"display_name": "Jane Smith",
|
||
|
|
"avatar_url": "https://...",
|
||
|
|
"followed_at": "2025-10-01T12:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": { /* ... */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/users/{id}/following`
|
||
|
|
**Description**: Get users followed by user.
|
||
|
|
|
||
|
|
**Response**: Same format as followers
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/users/{id}/follow`
|
||
|
|
**Description**: Follow a user.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"message": "Successfully followed user.",
|
||
|
|
"followed_at": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `409` - Already following (4009)
|
||
|
|
- `400` - Cannot follow yourself (4008)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `DELETE /api/v1/users/{id}/follow`
|
||
|
|
**Description**: Unfollow a user.
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/users/{id}/block`
|
||
|
|
**Description**: Block a user.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"reason": "Spam"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `DELETE /api/v1/users/{id}/block`
|
||
|
|
**Description**: Unblock a user.
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.3 Module: Tracks
|
||
|
|
|
||
|
|
#### `GET /api/v1/tracks`
|
||
|
|
**Description**: List all public tracks (discovery feed).
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `limit` (query, optional, default=20) - Page size
|
||
|
|
- `cursor` (query, optional) - Pagination cursor
|
||
|
|
- `genre` (query, optional) - Filter by genre
|
||
|
|
- `bpm_min`, `bpm_max` (query, optional) - BPM range
|
||
|
|
- `duration_min`, `duration_max` (query, optional) - Duration range (seconds)
|
||
|
|
- `sort` (query, optional, default=-created_at) - Sort field
|
||
|
|
- `search` (query, optional) - Full-text search
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"title": "Midnight Dreams",
|
||
|
|
"artist": "DJ Nova",
|
||
|
|
"duration": 245,
|
||
|
|
"genre": "Electronic",
|
||
|
|
"bpm": 128,
|
||
|
|
"musical_key": "Am",
|
||
|
|
"cover_art_url": "https://cdn.veza.io/covers/...",
|
||
|
|
"waveform_url": "https://cdn.veza.io/waveforms/...",
|
||
|
|
"creator": {
|
||
|
|
"id": "creator-uuid",
|
||
|
|
"username": "djnova",
|
||
|
|
"avatar_url": "https://..."
|
||
|
|
},
|
||
|
|
"play_count": 12500,
|
||
|
|
"like_count": 850,
|
||
|
|
"comment_count": 42,
|
||
|
|
"visibility": "public",
|
||
|
|
"is_downloadable": false,
|
||
|
|
"published_at": "2025-10-15T10:00:00Z",
|
||
|
|
"created_at": "2025-10-15T09:45:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": {
|
||
|
|
"next_cursor": "eyJpZCI6IjY2MWU5NTExIn0",
|
||
|
|
"has_more": true,
|
||
|
|
"limit": 20
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/tracks`
|
||
|
|
**Description**: Upload a new track.
|
||
|
|
|
||
|
|
**Headers**:
|
||
|
|
- `Authorization: Bearer {token}`
|
||
|
|
- `Content-Type: multipart/form-data`
|
||
|
|
|
||
|
|
**Permissions**: `creator`, `premium`, `admin`
|
||
|
|
|
||
|
|
**Request** (multipart/form-data):
|
||
|
|
```
|
||
|
|
title: "Midnight Dreams"
|
||
|
|
artist: "DJ Nova"
|
||
|
|
description: "A dreamy electronic track..."
|
||
|
|
genre: "Electronic"
|
||
|
|
bpm: 128
|
||
|
|
musical_key: "Am"
|
||
|
|
visibility: "public"
|
||
|
|
is_downloadable: false
|
||
|
|
file: (audio file)
|
||
|
|
cover_art: (image file, optional)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"title": "Midnight Dreams",
|
||
|
|
"status": "processing",
|
||
|
|
"message": "Track uploaded successfully. Processing waveform and metadata..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `403` - Insufficient permissions (1003)
|
||
|
|
- `400` - Invalid file type (2010)
|
||
|
|
- `400` - File too large (2009)
|
||
|
|
- `400` - Upload limit reached (4005)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/tracks/{id}`
|
||
|
|
**Description**: Get track details.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `id` (path, required) - Track UUID
|
||
|
|
- `include` (query, optional) - Related resources (`creator,stats,comments`)
|
||
|
|
|
||
|
|
**Response** (200 OK): Same as list item + full metadata
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `PATCH /api/v1/tracks/{id}`
|
||
|
|
**Description**: Update track metadata.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Permissions**: Track owner or admin
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"title": "Midnight Dreams (Remix)",
|
||
|
|
"description": "Updated description",
|
||
|
|
"genre": "House",
|
||
|
|
"visibility": "private"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK): Updated track object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `DELETE /api/v1/tracks/{id}`
|
||
|
|
**Description**: Delete track (soft delete).
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Permissions**: Track owner or admin
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/tracks/{id}/stream`
|
||
|
|
**Description**: Get streaming URL for track.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}` (optional for public tracks)
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"stream_url": "https://cdn.veza.io/streams/550e8400.m3u8",
|
||
|
|
"format": "hls",
|
||
|
|
"bitrates": [128, 256, 320],
|
||
|
|
"expires_at": "2025-11-02T15:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/tracks/{id}/like`
|
||
|
|
**Description**: Like a track.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"message": "Track liked successfully.",
|
||
|
|
"liked_at": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `DELETE /api/v1/tracks/{id}/like`
|
||
|
|
**Description**: Unlike a track.
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/tracks/{id}/likes`
|
||
|
|
**Description**: Get users who liked track.
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"user": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "jane_doe",
|
||
|
|
"avatar_url": "https://..."
|
||
|
|
},
|
||
|
|
"liked_at": "2025-11-01T12:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": { /* ... */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/tracks/{id}/comments`
|
||
|
|
**Description**: Get track comments.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `timestamp` (query, optional) - Filter by waveform timestamp
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "comment-uuid",
|
||
|
|
"user": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "commenter",
|
||
|
|
"avatar_url": "https://..."
|
||
|
|
},
|
||
|
|
"content": "Love the drop at 2:30!",
|
||
|
|
"timestamp_seconds": 150,
|
||
|
|
"created_at": "2025-11-01T14:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": { /* ... */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/tracks/{id}/comments`
|
||
|
|
**Description**: Add comment to track.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"content": "Amazing track!",
|
||
|
|
"timestamp_seconds": 150
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Comment object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.4 Module: Playlists
|
||
|
|
|
||
|
|
#### `GET /api/v1/playlists`
|
||
|
|
**Description**: List public playlists.
|
||
|
|
|
||
|
|
**Response**: Similar to tracks list
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/playlists`
|
||
|
|
**Description**: Create playlist.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"name": "My Favorites",
|
||
|
|
"description": "Best tracks of 2025",
|
||
|
|
"visibility": "public",
|
||
|
|
"is_collaborative": false
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "playlist-uuid",
|
||
|
|
"name": "My Favorites",
|
||
|
|
"description": "Best tracks of 2025",
|
||
|
|
"visibility": "public",
|
||
|
|
"is_collaborative": false,
|
||
|
|
"track_count": 0,
|
||
|
|
"duration_seconds": 0,
|
||
|
|
"created_at": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/playlists/{id}`
|
||
|
|
**Description**: Get playlist details with tracks.
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "playlist-uuid",
|
||
|
|
"name": "My Favorites",
|
||
|
|
"description": "Best tracks of 2025",
|
||
|
|
"owner": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "johndoe"
|
||
|
|
},
|
||
|
|
"tracks": [
|
||
|
|
{
|
||
|
|
"id": "track-uuid",
|
||
|
|
"title": "Track Title",
|
||
|
|
"position": 1,
|
||
|
|
"added_at": "2025-11-01T12:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"track_count": 15,
|
||
|
|
"duration_seconds": 3675,
|
||
|
|
"created_at": "2025-10-01T10:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/playlists/{id}/tracks`
|
||
|
|
**Description**: Add track to playlist.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"track_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"position": 1
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created)
|
||
|
|
|
||
|
|
**Errors**:
|
||
|
|
- `409` - Track already in playlist (3002)
|
||
|
|
- `400` - Playlist is full (4007)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `DELETE /api/v1/playlists/{id}/tracks/{track_id}`
|
||
|
|
**Description**: Remove track from playlist.
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `PATCH /api/v1/playlists/{id}/tracks/reorder`
|
||
|
|
**Description**: Reorder tracks in playlist.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"positions": [
|
||
|
|
{ "track_id": "uuid1", "position": 1 },
|
||
|
|
{ "track_id": "uuid2", "position": 2 }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (200 OK)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.5 Module: Chat & Messaging
|
||
|
|
|
||
|
|
#### `GET /api/v1/rooms`
|
||
|
|
**Description**: List user's chat rooms.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "room-uuid",
|
||
|
|
"name": "General Chat",
|
||
|
|
"room_type": "public",
|
||
|
|
"member_count": 1250,
|
||
|
|
"last_message": {
|
||
|
|
"content": "Hello everyone!",
|
||
|
|
"sender": {
|
||
|
|
"username": "jane_doe"
|
||
|
|
},
|
||
|
|
"created_at": "2025-11-02T14:25:00Z"
|
||
|
|
},
|
||
|
|
"unread_count": 5
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/rooms`
|
||
|
|
**Description**: Create chat room.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"name": "My Private Room",
|
||
|
|
"room_type": "private",
|
||
|
|
"max_members": 50
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Room object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/rooms/{id}/messages`
|
||
|
|
**Description**: Get room messages.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `limit` (query, optional, default=50)
|
||
|
|
- `before` (query, optional) - Message ID for pagination
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "message-uuid",
|
||
|
|
"sender": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "jane_doe",
|
||
|
|
"avatar_url": "https://..."
|
||
|
|
},
|
||
|
|
"content": "Hello everyone!",
|
||
|
|
"message_type": "text",
|
||
|
|
"created_at": "2025-11-02T14:25:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": { /* ... */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/rooms/{id}/messages`
|
||
|
|
**Description**: Send message to room.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"content": "Hello everyone!",
|
||
|
|
"message_type": "text",
|
||
|
|
"reply_to_id": "optional-message-uuid"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Message object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/direct-messages`
|
||
|
|
**Description**: List direct message conversations.
|
||
|
|
|
||
|
|
**Response**: List of conversations with last message
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/direct-messages`
|
||
|
|
**Description**: Send direct message.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"recipient_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
|
|
"content": "Hey, how are you?",
|
||
|
|
"message_type": "text"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Message object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.6 Module: Marketplace
|
||
|
|
|
||
|
|
#### `GET /api/v1/products`
|
||
|
|
**Description**: List marketplace products.
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `category` (query, optional) - Filter by category
|
||
|
|
- `price_min`, `price_max` (query, optional) - Price range
|
||
|
|
- `genre` (query, optional) - Filter by genre
|
||
|
|
- `sort` (query, optional) - Sort field
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"id": "product-uuid",
|
||
|
|
"name": "EDM Sample Pack Vol. 1",
|
||
|
|
"slug": "edm-sample-pack-vol-1",
|
||
|
|
"description": "100+ high-quality EDM samples",
|
||
|
|
"category": "sample",
|
||
|
|
"price": 29.99,
|
||
|
|
"currency": "USD",
|
||
|
|
"seller": {
|
||
|
|
"id": "uuid",
|
||
|
|
"username": "producer_pro"
|
||
|
|
},
|
||
|
|
"thumbnail_url": "https://...",
|
||
|
|
"preview_file_url": "https://...",
|
||
|
|
"sale_count": 450,
|
||
|
|
"average_rating": 4.8,
|
||
|
|
"review_count": 120
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"pagination": { /* ... */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/products`
|
||
|
|
**Description**: Create product listing.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Permissions**: `creator`, `admin`
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"name": "EDM Sample Pack Vol. 1",
|
||
|
|
"description": "100+ high-quality EDM samples...",
|
||
|
|
"category": "sample",
|
||
|
|
"price": 29.99,
|
||
|
|
"currency": "USD",
|
||
|
|
"tags": ["edm", "samples", "electronic"],
|
||
|
|
"download_file_ids": ["uuid1", "uuid2"],
|
||
|
|
"license_type": "Royalty-Free"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Product object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/products/{id}`
|
||
|
|
**Description**: Get product details.
|
||
|
|
|
||
|
|
**Response** (200 OK): Full product object with reviews
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/cart/items`
|
||
|
|
**Description**: Add product to cart.
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"product_id": "550e8400-e29b-41d4-a716-446655440000"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created): Cart object
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/cart`
|
||
|
|
**Description**: Get current user's cart.
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "cart-uuid",
|
||
|
|
"items": [
|
||
|
|
{
|
||
|
|
"product": {
|
||
|
|
"id": "uuid",
|
||
|
|
"name": "Sample Pack",
|
||
|
|
"price": 29.99
|
||
|
|
},
|
||
|
|
"added_at": "2025-11-02T14:00:00Z"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"item_count": 3,
|
||
|
|
"subtotal": 89.97,
|
||
|
|
"tax_total": 7.20,
|
||
|
|
"total": 97.17,
|
||
|
|
"currency": "USD"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `POST /api/v1/orders`
|
||
|
|
**Description**: Create order from cart (checkout).
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"payment_method": "stripe",
|
||
|
|
"billing_email": "user@example.com",
|
||
|
|
"discount_code": "SUMMER25"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (201 Created):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"order_id": "order-uuid",
|
||
|
|
"order_number": "ORD-2025-00001",
|
||
|
|
"status": "pending",
|
||
|
|
"total": 97.17,
|
||
|
|
"payment_intent_id": "pi_1234567890",
|
||
|
|
"client_secret": "pi_1234567890_secret_..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/orders/{id}`
|
||
|
|
**Description**: Get order details.
|
||
|
|
|
||
|
|
**Response** (200 OK): Full order object with items
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/orders`
|
||
|
|
**Description**: List user's orders.
|
||
|
|
|
||
|
|
**Response** (200 OK): List of orders
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.7 Module: Search
|
||
|
|
|
||
|
|
#### `GET /api/v1/search`
|
||
|
|
**Description**: Global search (tracks, users, playlists, products).
|
||
|
|
|
||
|
|
**Parameters**:
|
||
|
|
- `q` (query, required) - Search query
|
||
|
|
- `type` (query, optional) - Filter by type (`tracks`, `users`, `playlists`, `products`)
|
||
|
|
- `limit` (query, optional, default=20)
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"tracks": {
|
||
|
|
"data": [ /* track objects */ ],
|
||
|
|
"total": 150
|
||
|
|
},
|
||
|
|
"users": {
|
||
|
|
"data": [ /* user objects */ ],
|
||
|
|
"total": 25
|
||
|
|
},
|
||
|
|
"playlists": {
|
||
|
|
"data": [ /* playlist objects */ ],
|
||
|
|
"total": 40
|
||
|
|
},
|
||
|
|
"products": {
|
||
|
|
"data": [ /* product objects */ ],
|
||
|
|
"total": 30
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 7.8 Module: Analytics
|
||
|
|
|
||
|
|
#### `POST /api/v1/analytics/events`
|
||
|
|
**Description**: Track analytics event (client-side tracking).
|
||
|
|
|
||
|
|
**Request**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"event_type": "track_play",
|
||
|
|
"event_data": {
|
||
|
|
"track_id": "uuid",
|
||
|
|
"duration_played": 120,
|
||
|
|
"completion_percentage": 50
|
||
|
|
},
|
||
|
|
"metadata": {
|
||
|
|
"user_agent": "...",
|
||
|
|
"referrer": "..."
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response** (204 No Content)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### `GET /api/v1/analytics/tracks/{id}`
|
||
|
|
**Description**: Get track analytics.
|
||
|
|
|
||
|
|
**Headers**: `Authorization: Bearer {token}`
|
||
|
|
|
||
|
|
**Permissions**: Track owner or admin
|
||
|
|
|
||
|
|
**Response** (200 OK):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"track_id": "uuid",
|
||
|
|
"plays_total": 12500,
|
||
|
|
"plays_unique": 8500,
|
||
|
|
"likes_total": 850,
|
||
|
|
"comments_total": 42,
|
||
|
|
"plays_by_country": {
|
||
|
|
"US": 5000,
|
||
|
|
"UK": 2500,
|
||
|
|
"CA": 1500
|
||
|
|
},
|
||
|
|
"plays_by_day": [
|
||
|
|
{ "date": "2025-11-01", "plays": 450 },
|
||
|
|
{ "date": "2025-11-02", "plays": 520 }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
*[7.9-7.15 Other modules follow similar patterns]*
|
||
|
|
|
||
|
|
## 8. WEBSOCKET APIS
|
||
|
|
|
||
|
|
### 8.1 Connection
|
||
|
|
|
||
|
|
**URL**: `wss://api.veza.io/ws`
|
||
|
|
|
||
|
|
**Authentication**: Send JWT in first message
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "auth",
|
||
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "auth_success",
|
||
|
|
"user_id": "550e8400-e29b-41d4-a716-446655440000"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8.2 Message Types
|
||
|
|
|
||
|
|
#### Client → Server
|
||
|
|
|
||
|
|
**Join Room**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "join_room",
|
||
|
|
"room_id": "room-uuid"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Leave Room**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "leave_room",
|
||
|
|
"room_id": "room-uuid"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Send Message**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "message",
|
||
|
|
"room_id": "room-uuid",
|
||
|
|
"content": "Hello!",
|
||
|
|
"message_type": "text"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Typing Indicator**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "typing_start",
|
||
|
|
"room_id": "room-uuid"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Server → Client
|
||
|
|
|
||
|
|
**New Message**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "message",
|
||
|
|
"room_id": "room-uuid",
|
||
|
|
"message": {
|
||
|
|
"id": "message-uuid",
|
||
|
|
"sender": { /* user object */ },
|
||
|
|
"content": "Hello!",
|
||
|
|
"created_at": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**User Joined**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "user_joined",
|
||
|
|
"room_id": "room-uuid",
|
||
|
|
"user": { /* user object */ }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**User Left**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "user_left",
|
||
|
|
"room_id": "room-uuid",
|
||
|
|
"user_id": "uuid"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Typing Indicator**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "typing",
|
||
|
|
"room_id": "room-uuid",
|
||
|
|
"user": { /* user object */ },
|
||
|
|
"is_typing": true
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Presence Update**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "presence",
|
||
|
|
"user_id": "uuid",
|
||
|
|
"status": "online",
|
||
|
|
"last_seen_at": "2025-11-02T14:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8.3 Error Handling
|
||
|
|
|
||
|
|
**Error Message**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"type": "error",
|
||
|
|
"error": {
|
||
|
|
"code": 1002,
|
||
|
|
"message": "Invalid token"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8.4 Heartbeat
|
||
|
|
|
||
|
|
**Client sends**:
|
||
|
|
```json
|
||
|
|
{ "type": "ping" }
|
||
|
|
```
|
||
|
|
|
||
|
|
**Server responds**:
|
||
|
|
```json
|
||
|
|
{ "type": "pong" }
|
||
|
|
```
|
||
|
|
|
||
|
|
Interval: Every 30 seconds
|
||
|
|
|
||
|
|
## 9. GRPC APIS
|
||
|
|
|
||
|
|
### 9.1 Service: StreamService
|
||
|
|
|
||
|
|
**Proto Definition**:
|
||
|
|
```protobuf
|
||
|
|
syntax = "proto3";
|
||
|
|
|
||
|
|
package veza.stream.v1;
|
||
|
|
|
||
|
|
service StreamService {
|
||
|
|
rpc GetStreamURL(GetStreamURLRequest) returns (GetStreamURLResponse);
|
||
|
|
rpc RecordPlayback(RecordPlaybackRequest) returns (RecordPlaybackResponse);
|
||
|
|
rpc GetWaveform(GetWaveformRequest) returns (GetWaveformResponse);
|
||
|
|
}
|
||
|
|
|
||
|
|
message GetStreamURLRequest {
|
||
|
|
string track_id = 1;
|
||
|
|
string user_id = 2;
|
||
|
|
int32 bitrate = 3; // optional, default 320
|
||
|
|
}
|
||
|
|
|
||
|
|
message GetStreamURLResponse {
|
||
|
|
string stream_url = 1;
|
||
|
|
int32 bitrate = 2;
|
||
|
|
string format = 3;
|
||
|
|
int64 expires_at = 4;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 9.2 Service: ChatService
|
||
|
|
|
||
|
|
```protobuf
|
||
|
|
service ChatService {
|
||
|
|
rpc SendMessage(SendMessageRequest) returns (SendMessageResponse);
|
||
|
|
rpc GetMessages(GetMessagesRequest) returns (stream Message);
|
||
|
|
rpc GetRoomPresence(GetRoomPresenceRequest) returns (GetRoomPresenceResponse);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
*[Additional gRPC services defined for inter-service communication]*
|
||
|
|
|
||
|
|
## 10. OPENAPI 3.0 SPECIFICATION
|
||
|
|
|
||
|
|
### 10.1 Metadata
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
openapi: 3.0.3
|
||
|
|
info:
|
||
|
|
title: Veza API
|
||
|
|
version: 1.0.0
|
||
|
|
description: |
|
||
|
|
Veza platform API - Collaborative audio streaming, marketplace, and social network.
|
||
|
|
|
||
|
|
**Authentication**: JWT Bearer token in `Authorization` header.
|
||
|
|
|
||
|
|
**Rate Limiting**: Varies by endpoint (see headers).
|
||
|
|
|
||
|
|
**Support**: api@veza.io
|
||
|
|
contact:
|
||
|
|
name: Veza API Support
|
||
|
|
email: api@veza.io
|
||
|
|
url: https://docs.veza.io
|
||
|
|
license:
|
||
|
|
name: Proprietary
|
||
|
|
servers:
|
||
|
|
- url: https://api.veza.io/api/v1
|
||
|
|
description: Production
|
||
|
|
- url: https://staging-api.veza.io/api/v1
|
||
|
|
description: Staging
|
||
|
|
- url: http://localhost:8080/api/v1
|
||
|
|
description: Local Development
|
||
|
|
```
|
||
|
|
|
||
|
|
### 10.2 Security Schemes
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
components:
|
||
|
|
securitySchemes:
|
||
|
|
BearerAuth:
|
||
|
|
type: http
|
||
|
|
scheme: bearer
|
||
|
|
bearerFormat: JWT
|
||
|
|
description: JWT access token obtained from /auth/login
|
||
|
|
```
|
||
|
|
|
||
|
|
### 10.3 Common Schemas
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
components:
|
||
|
|
schemas:
|
||
|
|
UUID:
|
||
|
|
type: string
|
||
|
|
format: uuid
|
||
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
||
|
|
|
||
|
|
Timestamp:
|
||
|
|
type: string
|
||
|
|
format: date-time
|
||
|
|
example: "2025-11-02T14:30:00Z"
|
||
|
|
|
||
|
|
Error:
|
||
|
|
type: object
|
||
|
|
required:
|
||
|
|
- code
|
||
|
|
- message
|
||
|
|
properties:
|
||
|
|
code:
|
||
|
|
type: integer
|
||
|
|
example: 1001
|
||
|
|
message:
|
||
|
|
type: string
|
||
|
|
example: "Token expired"
|
||
|
|
details:
|
||
|
|
type: array
|
||
|
|
items:
|
||
|
|
type: object
|
||
|
|
properties:
|
||
|
|
field:
|
||
|
|
type: string
|
||
|
|
message:
|
||
|
|
type: string
|
||
|
|
request_id:
|
||
|
|
$ref: '#/components/schemas/UUID'
|
||
|
|
timestamp:
|
||
|
|
$ref: '#/components/schemas/Timestamp'
|
||
|
|
|
||
|
|
Pagination:
|
||
|
|
type: object
|
||
|
|
properties:
|
||
|
|
next_cursor:
|
||
|
|
type: string
|
||
|
|
nullable: true
|
||
|
|
has_more:
|
||
|
|
type: boolean
|
||
|
|
limit:
|
||
|
|
type: integer
|
||
|
|
```
|
||
|
|
|
||
|
|
### 10.4 Example Endpoint Definition
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
paths:
|
||
|
|
/tracks:
|
||
|
|
get:
|
||
|
|
summary: List tracks
|
||
|
|
description: Get a paginated list of public tracks
|
||
|
|
operationId: listTracks
|
||
|
|
tags:
|
||
|
|
- Tracks
|
||
|
|
parameters:
|
||
|
|
- name: limit
|
||
|
|
in: query
|
||
|
|
schema:
|
||
|
|
type: integer
|
||
|
|
default: 20
|
||
|
|
minimum: 1
|
||
|
|
maximum: 100
|
||
|
|
- name: cursor
|
||
|
|
in: query
|
||
|
|
schema:
|
||
|
|
type: string
|
||
|
|
- name: genre
|
||
|
|
in: query
|
||
|
|
schema:
|
||
|
|
type: string
|
||
|
|
- name: sort
|
||
|
|
in: query
|
||
|
|
schema:
|
||
|
|
type: string
|
||
|
|
default: "-created_at"
|
||
|
|
responses:
|
||
|
|
'200':
|
||
|
|
description: Success
|
||
|
|
content:
|
||
|
|
application/json:
|
||
|
|
schema:
|
||
|
|
type: object
|
||
|
|
properties:
|
||
|
|
data:
|
||
|
|
type: array
|
||
|
|
items:
|
||
|
|
$ref: '#/components/schemas/Track'
|
||
|
|
pagination:
|
||
|
|
$ref: '#/components/schemas/Pagination'
|
||
|
|
'400':
|
||
|
|
description: Bad Request
|
||
|
|
content:
|
||
|
|
application/json:
|
||
|
|
schema:
|
||
|
|
$ref: '#/components/schemas/Error'
|
||
|
|
|
||
|
|
post:
|
||
|
|
summary: Upload track
|
||
|
|
description: Upload a new audio track
|
||
|
|
operationId: createTrack
|
||
|
|
tags:
|
||
|
|
- Tracks
|
||
|
|
security:
|
||
|
|
- BearerAuth: []
|
||
|
|
requestBody:
|
||
|
|
required: true
|
||
|
|
content:
|
||
|
|
multipart/form-data:
|
||
|
|
schema:
|
||
|
|
type: object
|
||
|
|
required:
|
||
|
|
- title
|
||
|
|
- file
|
||
|
|
properties:
|
||
|
|
title:
|
||
|
|
type: string
|
||
|
|
minLength: 1
|
||
|
|
maxLength: 255
|
||
|
|
artist:
|
||
|
|
type: string
|
||
|
|
maxLength: 255
|
||
|
|
genre:
|
||
|
|
type: string
|
||
|
|
file:
|
||
|
|
type: string
|
||
|
|
format: binary
|
||
|
|
cover_art:
|
||
|
|
type: string
|
||
|
|
format: binary
|
||
|
|
responses:
|
||
|
|
'201':
|
||
|
|
description: Created
|
||
|
|
content:
|
||
|
|
application/json:
|
||
|
|
schema:
|
||
|
|
$ref: '#/components/schemas/Track'
|
||
|
|
'400':
|
||
|
|
$ref: '#/components/responses/BadRequest'
|
||
|
|
'401':
|
||
|
|
$ref: '#/components/responses/Unauthorized'
|
||
|
|
'403':
|
||
|
|
$ref: '#/components/responses/Forbidden'
|
||
|
|
```
|
||
|
|
|
||
|
|
*[Full OpenAPI 3.0 spec with all 500+ endpoints would be ~5,000 lines - included in separate YAML file]*
|
||
|
|
|
||
|
|
## ✅ CHECKLIST DE VALIDATION
|
||
|
|
|
||
|
|
### API Completeness
|
||
|
|
- [ ] 500+ endpoints documentés pour tous les modules
|
||
|
|
- [ ] Request/Response schemas complets
|
||
|
|
- [ ] Authentication flows documentés
|
||
|
|
- [ ] Error codes standardisés (1000-9999)
|
||
|
|
- [ ] WebSocket protocol spécifié
|
||
|
|
- [ ] gRPC services définis
|
||
|
|
|
||
|
|
### Consistency
|
||
|
|
- [ ] Naming conventions respectées (snake_case, plural resources)
|
||
|
|
- [ ] HTTP methods utilisés correctement
|
||
|
|
- [ ] Dates format ISO 8601
|
||
|
|
- [ ] UUIDs pour tous les IDs
|
||
|
|
- [ ] Pagination cohérente (cursor-based)
|
||
|
|
|
||
|
|
### Security
|
||
|
|
- [ ] JWT authentication implémentée
|
||
|
|
- [ ] Rate limiting sur tous les endpoints
|
||
|
|
- [ ] Permission checks documentés
|
||
|
|
- [ ] Sensitive data jamais en query params
|
||
|
|
|
||
|
|
### Performance
|
||
|
|
- [ ] Pagination obligatoire pour collections
|
||
|
|
- [ ] Field selection supportée
|
||
|
|
- [ ] Caching headers définis
|
||
|
|
- [ ] Compression activée (gzip)
|
||
|
|
|
||
|
|
## 📊 MÉTRIQUES DE SUCCÈS
|
||
|
|
|
||
|
|
### Performance Targets
|
||
|
|
- **API Response Time p95**: < 100ms
|
||
|
|
- **API Response Time p99**: < 500ms
|
||
|
|
- **Throughput**: 10,000 req/s
|
||
|
|
- **Availability**: 99.95%
|
||
|
|
|
||
|
|
### Developer Experience
|
||
|
|
- **Time to First API Call**: < 5 minutes
|
||
|
|
- **Documentation Completeness**: 100%
|
||
|
|
- **API Error Rate**: < 0.1%
|
||
|
|
- **Breaking Changes**: 0 in v1
|
||
|
|
|
||
|
|
## 🔄 HISTORIQUE DES VERSIONS
|
||
|
|
|
||
|
|
| Version | Date | Changements |
|
||
|
|
|---------|------|-------------|
|
||
|
|
| 1.0.0 | 2025-11-02 | Version initiale - API REST complète |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⚠️ AVERTISSEMENT
|
||
|
|
|
||
|
|
**CETTE SPÉCIFICATION EST IMMUABLE**
|
||
|
|
|
||
|
|
L'API v1 définie ici est **VERROUILLÉE**. Toute modification nécessite:
|
||
|
|
|
||
|
|
1. **RFC API Change** avec impact analysis
|
||
|
|
2. **Backward compatibility** garantie
|
||
|
|
3. **Deprecation notice** (6 mois minimum)
|
||
|
|
4. **Migration guide** pour clients existants
|
||
|
|
5. **Approbation CTO**
|
||
|
|
|
||
|
|
**Breaking changes INTERDITS en v1** - Créer v2 si nécessaire.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Document créé par**: API Team + Architecture
|
||
|
|
**Date de création**: 2025-11-02
|
||
|
|
**Prochaine révision**: Phase 4 (Q3 2026)
|
||
|
|
**Propriétaire**: Lead Backend Engineer
|
||
|
|
|
||
|
|
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|