basePath: /api/v1 definitions: internal_core_track.BatchDeleteRequest: properties: track_ids: items: type: string minItems: 1 type: array required: - track_ids type: object internal_core_track.BatchUpdateRequest: properties: track_ids: items: type: string minItems: 1 type: array updates: additionalProperties: true type: object required: - track_ids - updates type: object internal_core_track.CompleteChunkedUploadRequest: properties: upload_id: type: string required: - upload_id type: object internal_core_track.CreateShareRequest: properties: expires_at: type: string permissions: enum: - read - write - admin type: string required: - permissions type: object internal_core_track.InitiateChunkedUploadRequest: properties: filename: type: string total_chunks: minimum: 1 type: integer total_size: minimum: 1 type: integer required: - filename - total_chunks - total_size type: object internal_core_track.RecordPlayRequest: properties: play_time: minimum: 0 type: integer type: object internal_core_track.StreamCallbackRequest: properties: error: type: string manifest_url: type: string status: enum: - completed - failed - processing type: string required: - status type: object internal_core_track.UpdateLyricsRequest: properties: content: type: string type: object internal_core_track.UpdateTrackRequest: properties: album: maxLength: 255 type: string artist: maxLength: 255 type: string bpm: maximum: 300 minimum: 0 type: integer genre: description: legacy, single maxLength: 100 type: string genres: description: 'v0.10.1: max 3, taxonomy slugs' items: type: string type: array is_public: type: boolean musical_key: maxLength: 10 type: string tags: description: 'v0.10.1: max 10, 30 chars each' items: type: string type: array title: maxLength: 255 minLength: 1 type: string year: maximum: 2100 minimum: 1900 type: integer type: object internal_handlers.APIResponse: properties: data: {} error: {} success: type: boolean type: object internal_handlers.AddCollaboratorRequest: properties: permission: enum: - read - write - admin type: string user_id: type: string required: - permission - user_id type: object internal_handlers.AddQueueItemRequest: properties: track_id: type: string required: - track_id type: object internal_handlers.AddToSessionRequest: properties: track_id: type: string required: - track_id type: object internal_handlers.CreateCommentRequest: properties: content: maxLength: 5000 minLength: 1 type: string parent_id: type: string timestamp: description: Position in seconds (0 = top-level, no specific time) type: number required: - content type: object internal_handlers.CreateOrderRequest: properties: items: items: properties: product_id: type: string required: - product_id type: object minItems: 1 type: array promo_code: maxLength: 50 type: string required: - items type: object internal_handlers.CreatePlaylistRequest: properties: description: maxLength: 1000 type: string is_public: type: boolean title: maxLength: 200 minLength: 1 type: string required: - title type: object internal_handlers.CreateProductRequest: properties: bpm: description: v0.401 M1 maximum: 300 minimum: 1 type: integer category: enum: - sample - beat - preset - pack type: string description: maxLength: 2000 type: string license_type: enum: - standard - exclusive - commercial type: string licenses: description: 'v0.401 M2: Product licenses (streaming, personal, commercial, exclusive)' items: properties: license_type: enum: - streaming - personal - commercial - exclusive type: string price_cents: minimum: 0 type: integer terms_text: type: string required: - license_type - price_cents type: object type: array musical_key: maxLength: 10 type: string price: minimum: 0 type: number product_type: enum: - track - pack - service type: string title: maxLength: 200 minLength: 3 type: string track_id: description: UUID string type: string required: - price - product_type - title type: object internal_handlers.DashboardResponse: properties: library_preview: $ref: '#/definitions/internal_handlers.LibraryPreview' recent_activity: items: $ref: '#/definitions/internal_handlers.RecentActivity' type: array stats: $ref: '#/definitions/internal_handlers.DashboardStats' type: object internal_handlers.DashboardStats: properties: active_friends: type: integer active_friends_change: type: string favorites: type: integer favorites_change: type: string messages_sent: type: integer messages_sent_change: type: string period: type: string tracks_played: type: integer tracks_played_change: type: string type: object internal_handlers.DeleteAccountRequest: properties: confirm_text: type: string keep_public_tracks: description: If true, public tracks remain (attributed to deleted account) type: boolean password: type: string reason: type: string required: - confirm_text - password type: object internal_handlers.DisableTwoFactorRequest: properties: password: type: string required: - password type: object internal_handlers.FrontendLogRequest: properties: context: additionalProperties: true type: object data: {} level: type: string message: type: string timestamp: type: string type: object internal_handlers.ImportPlaylistRequest: properties: playlist: properties: description: type: string is_public: type: boolean title: type: string type: object tracks: items: properties: id: type: string type: object type: array type: object internal_handlers.LibraryPreview: properties: has_more: type: boolean items: items: $ref: '#/definitions/internal_handlers.TrackPreview' type: array total_count: type: integer type: object internal_handlers.RecentActivity: properties: description: type: string icon: type: string id: type: string metadata: additionalProperties: true type: object timestamp: type: string title: type: string type: type: string type: object internal_handlers.ReorderTracksRequest: properties: track_ids: description: Changed to []uuid.UUID items: type: string minItems: 1 type: array required: - track_ids type: object internal_handlers.RequestPasswordResetRequest: properties: email: type: string required: - email type: object internal_handlers.ResetPasswordRequest: properties: new_password: minLength: 12 type: string token: type: string required: - new_password - token type: object internal_handlers.SetupTwoFactorResponse: properties: qr_code_url: type: string recovery_codes: items: type: string type: array secret: type: string type: object internal_handlers.StreamTokenResponse: properties: expires_in: description: seconds type: integer token: type: string type: object internal_handlers.TrackPreview: properties: artist: type: string cover_art_path: type: string created_at: type: string duration: type: integer id: type: string like_count: type: integer play_count: type: integer title: type: string type: object internal_handlers.UpdateCollaboratorPermissionRequest: properties: permission: enum: - read - write - admin type: string required: - permission type: object internal_handlers.UpdateCommentRequest: properties: content: maxLength: 5000 minLength: 1 type: string required: - content type: object internal_handlers.UpdatePlaylistRequest: properties: description: maxLength: 1000 type: string is_public: type: boolean title: maxLength: 200 minLength: 1 type: string type: object internal_handlers.UpdateProductRequest: properties: bpm: maximum: 300 minimum: 1 type: integer category: enum: - sample - beat - preset - pack type: string description: maxLength: 2000 type: string licenses: description: 'v0.401 M2: Product licenses' items: properties: license_type: enum: - streaming - personal - commercial - exclusive type: string price_cents: minimum: 0 type: integer terms_text: type: string required: - license_type - price_cents type: object type: array musical_key: maxLength: 10 type: string price: minimum: 0 type: number status: enum: - draft - active - archived type: string title: maxLength: 200 minLength: 3 type: string type: object internal_handlers.UpdateProfileRequest: properties: banner_url: maxLength: 2048 type: string bio: maxLength: 500 type: string birthdate: type: string first_name: maxLength: 100 type: string gender: enum: - Male - Female - Other - Prefer not to say type: string is_public: type: boolean last_name: maxLength: 100 type: string location: maxLength: 100 type: string social_links: additionalProperties: true type: object username: maxLength: 30 minLength: 3 type: string type: object internal_handlers.ValidateRequest: properties: data: description: The data to validate items: type: integer type: array type: description: e.g., "RegisterRequest", "LoginRequest" type: string required: - data - type type: object internal_handlers.ValidateResponse: properties: errors: items: $ref: '#/definitions/veza-backend-api_internal_dto.ValidationError' type: array message: type: string valid: type: boolean type: object internal_handlers.VerifyTwoFactorRequest: properties: code: description: TOTP code to verify type: string secret: description: Secret from setup step type: string required: - code - secret type: object veza-backend-api_internal_core_marketplace.LicenseType: enum: - basic - premium - exclusive type: string x-enum-varnames: - LicenseBasic - LicensePremium - LicenseExclusive veza-backend-api_internal_core_marketplace.Order: properties: buyer_id: type: string created_at: type: string currency: type: string discount_amount_cents: type: integer hyperswitch_payment_id: type: string id: type: string items: items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.OrderItem' type: array payment_intent: description: Legacy / Stripe PaymentIntent ID type: string payment_status: description: Hyperswitch payment status type: string promo_code_id: type: string refund_deadline: description: 'v0.12.0: 14-day refund deadline' type: string status: description: pending, completed, failed, refunded type: string total_amount: type: number updated_at: type: string type: object veza-backend-api_internal_core_marketplace.OrderItem: properties: id: type: string order_id: type: string price: type: number product_id: type: string type: object veza-backend-api_internal_core_marketplace.Product: properties: avg_rating: description: 'v0.403 R1: Computed from product_reviews (not stored in DB)' type: number bpm: description: 'v0.401 M1: Métadonnées musicales et catégorie' type: integer category: description: sample, beat, preset, pack type: string created_at: type: string currency: type: string description: type: string id: type: string images: items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.ProductImage' type: array license_type: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.LicenseType' licenses: items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.ProductLicense' type: array musical_key: type: string previews: description: Relations items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.ProductPreview' type: array price: type: number product_type: description: '"track", "pack", "service"' type: string review_count: type: integer seller_id: type: string status: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.ProductStatus' title: type: string track_id: description: Liaison optionnelle avec un Track (si ProductType == "track") type: string updated_at: type: string type: object veza-backend-api_internal_core_marketplace.ProductImage: properties: created_at: type: string id: type: string product_id: type: string sort_order: type: integer url: type: string type: object veza-backend-api_internal_core_marketplace.ProductLicense: properties: created_at: type: string id: type: string license_type: description: streaming, personal, commercial, exclusive type: string price_cents: type: integer product_id: type: string terms_text: type: string type: object veza-backend-api_internal_core_marketplace.ProductPreview: properties: created_at: type: string duration_sec: type: integer file_path: type: string id: type: string product_id: type: string type: object veza-backend-api_internal_core_marketplace.ProductStatus: enum: - draft - active - archived type: string x-enum-varnames: - ProductStatusDraft - ProductStatusActive - ProductStatusArchived veza-backend-api_internal_dto.LoginRequest: properties: email: type: string password: type: string remember_me: type: boolean required: - email - password type: object veza-backend-api_internal_dto.LoginResponse: properties: requires_2fa: description: 'BE-API-001: Flag indicating 2FA is required' type: boolean token: $ref: '#/definitions/veza-backend-api_internal_dto.TokenResponse' user: $ref: '#/definitions/veza-backend-api_internal_dto.UserResponse' type: object veza-backend-api_internal_dto.RefreshRequest: properties: refresh_token: type: string required: - refresh_token type: object veza-backend-api_internal_dto.RegisterRequest: properties: email: type: string password: minLength: 12 type: string password_confirmation: type: string username: maxLength: 50 minLength: 3 type: string required: - email - password - password_confirmation type: object veza-backend-api_internal_dto.RegisterResponse: properties: message: type: string user: $ref: '#/definitions/veza-backend-api_internal_dto.UserResponse' verification_required: type: boolean type: object veza-backend-api_internal_dto.ResendVerificationRequest: properties: email: type: string required: - email type: object veza-backend-api_internal_dto.TokenResponse: properties: access_token: type: string expires_in: type: integer refresh_token: type: string type: object veza-backend-api_internal_dto.UserResponse: properties: email: type: string id: type: string username: type: string type: object veza-backend-api_internal_dto.ValidationError: properties: field: type: string message: type: string value: type: string type: object veza-backend-api_internal_handlers.APIResponse: properties: data: {} error: {} success: type: boolean type: object veza-backend-api_internal_models.Playlist: properties: collaborators: items: $ref: '#/definitions/veza-backend-api_internal_models.PlaylistCollaborator' type: array cover_url: type: string created_at: type: string description: type: string follower_count: type: integer id: type: string is_default_favorites: description: v0.10.4 F136 type: boolean is_editorial: description: v0.10.4 F141 type: boolean is_public: type: boolean title: type: string track_count: type: integer tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.PlaylistTrack' type: array updated_at: type: string user_id: type: string type: object veza-backend-api_internal_models.PlaylistCollaborator: properties: created_at: type: string id: type: string permission: $ref: '#/definitions/veza-backend-api_internal_models.PlaylistPermission' playlist_id: type: string updated_at: type: string user: $ref: '#/definitions/veza-backend-api_internal_models.User' user_id: type: string type: object veza-backend-api_internal_models.PlaylistPermission: enum: - read - write - admin type: string x-enum-varnames: - PlaylistPermissionRead - PlaylistPermissionWrite - PlaylistPermissionAdmin veza-backend-api_internal_models.PlaylistTrack: properties: added_at: type: string added_by: type: string id: type: string playlist_id: type: string position: type: integer track: $ref: '#/definitions/veza-backend-api_internal_models.Track' track_id: type: string type: object veza-backend-api_internal_models.Track: properties: album: type: string artist: type: string bitrate: description: kbps type: integer bpm: type: integer cover_art_path: type: string created_at: type: string creator_id: type: string duration: description: seconds type: integer file_id: description: NULL temporairement avant création fichier type: string file_path: type: string file_size: description: bytes type: integer format: description: mp3, flac, wav, etc. type: string genre: type: string id: type: string is_public: type: boolean musical_key: type: string sample_rate: description: Hz type: integer status: $ref: '#/definitions/veza-backend-api_internal_models.TrackStatus' status_message: type: string stream_manifest_url: type: string stream_status: description: pending, processing, ready, error type: string tags: items: type: string type: array title: type: string updated_at: type: string waveform_path: type: string waveform_url: type: string year: type: integer type: object veza-backend-api_internal_models.TrackStatus: enum: - uploading - processing - completed - failed type: string x-enum-varnames: - TrackStatusUploading - TrackStatusProcessing - TrackStatusCompleted - TrackStatusFailed veza-backend-api_internal_models.User: properties: avatar: type: string banner_url: type: string bio: type: string birthdate: type: string created_at: type: string email: type: string first_name: type: string gender: type: string id: type: string is_active: type: boolean is_admin: type: boolean is_banned: type: boolean is_public: type: boolean is_verified: type: boolean last_login_at: type: string last_name: type: string location: type: string login_count: type: integer password: description: Virtual field for input type: string password_changed_at: description: 'F016: Password expiration tracking' type: string promoted_to_creator_at: description: |- v1.0.6: set the first time a user self-promotes to `role='creator'` via POST /api/v1/users/me/upgrade-creator. NULL for users who never took that path (still 'user', or promoted by an admin out-of-band). type: string role: type: string slug: type: string social_links: type: string token_version: type: integer updated_at: type: string username: type: string username_changed_at: type: string type: object veza-backend-api_internal_response.APIResponse: properties: data: {} error: {} success: type: boolean type: object veza-backend-api_internal_services.UpdateQueueRequest: properties: current_position: type: integer current_track_id: type: string is_playing: type: boolean item_order: items: type: string type: array repeat_mode: type: string shuffle: type: boolean volume: type: integer type: object host: localhost:18080 info: contact: email: support@veza.app name: API Support url: http://www.veza.app/support description: Backend API for Veza platform. license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html termsOfService: http://swagger.io/terms/ title: Veza Backend API version: 1.2.0 paths: /api/v1/dashboard: get: consumes: - application/json description: Get aggregated dashboard data including stats, recent activity, and library preview parameters: - description: 'Number of recent activity items (default: 10)' in: query name: activity_limit type: integer - description: 'Number of library items (default: 5)' in: query name: library_limit type: integer - description: 'Time period for statistics: 7d, 30d, 90d, all (default: 30d)' in: query name: stats_period type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: $ref: '#/definitions/internal_handlers.DashboardResponse' type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Dashboard Data tags: - Dashboard /api/v1/logs/frontend: post: consumes: - application/json description: Receive and store a log entry from the frontend application parameters: - description: Frontend log entry in: body name: log required: true schema: $ref: '#/definitions/internal_handlers.FrontendLogRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: received: type: boolean type: object type: object "400": description: Invalid log entry schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Receive frontend log tags: - Logging /api/v1/marketplace/download/{product_id}: get: consumes: - application/json description: Get a secure download URL for a purchased product parameters: - description: Product ID in: path name: product_id required: true type: string produces: - application/json responses: "200": description: OK schema: additionalProperties: type: string type: object "403": description: No license schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Not Found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Get download URL tags: - Marketplace /api/v1/marketplace/orders: get: consumes: - application/json description: Get all orders for the authenticated user produces: - application/json responses: "200": description: OK schema: items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Order' type: array "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: List user orders tags: - Marketplace post: consumes: - application/json description: Purchase products parameters: - description: Order items in: body name: order required: true schema: $ref: '#/definitions/internal_handlers.CreateOrderRequest' produces: - application/json responses: "201": description: Created schema: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Order' "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Create a new order tags: - Marketplace /api/v1/marketplace/orders/{id}: get: consumes: - application/json description: Get details of a specific order (only order owner can access) parameters: - description: Order ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Order' "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Forbidden - Not order owner schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Order not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Get order details tags: - Marketplace /api/v1/marketplace/products: get: consumes: - application/json description: List marketplace products with filters parameters: - description: Product status in: query name: status type: string - description: Seller ID in: query name: seller_id type: string - description: Search query in: query name: q type: string - description: Product type (track, pack, service) in: query name: type type: string - description: Minimum price in: query name: min_price type: number - description: Maximum price in: query name: max_price type: number - description: Page number in: query name: page type: integer - description: Items per page in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: items: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Product' type: array summary: List products tags: - Marketplace post: consumes: - application/json description: Create a product (Track, Pack, Service) for sale parameters: - description: Product info in: body name: product required: true schema: $ref: '#/definitions/internal_handlers.CreateProductRequest' produces: - application/json responses: "201": description: Created schema: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Product' "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Create a new product tags: - Marketplace /api/v1/marketplace/products/{id}: put: consumes: - application/json description: Update product details (only seller can update) parameters: - description: Product ID in: path name: id required: true type: string - description: Product updates in: body name: product required: true schema: $ref: '#/definitions/internal_handlers.UpdateProductRequest' produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/veza-backend-api_internal_core_marketplace.Product' "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Forbidden - Not product owner schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Product not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Update a product tags: - Marketplace /audit/activity: get: consumes: - application/json description: Get recent activity logs for the current user parameters: - default: 50 description: Number of activities to return in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: activities: type: array type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get user activity tags: - Audit /audit/logs: get: consumes: - application/json description: Search and filter audit logs with pagination support. Supports filtering by action, resource, date range, IP address, and user agent. parameters: - description: Filter by action type in: query name: action type: string - description: Filter by resource type in: query name: resource type: string - description: Filter by resource ID (UUID) in: query name: resource_id type: string - description: Filter by IP address in: query name: ip_address type: string - description: Filter by user agent in: query name: user_agent type: string - description: Start date filter (YYYY-MM-DD) in: query name: start_date type: string - description: End date filter (YYYY-MM-DD) in: query name: end_date type: string - default: 1 description: Page number in: query name: page type: integer - default: 20 description: Items per page in: query name: limit type: integer - description: Offset for pagination in: query name: offset type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: logs: type: array pagination: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Search audit logs tags: - Audit /audit/stats: get: consumes: - application/json description: Get audit statistics for the current user, optionally filtered by date range parameters: - description: Start date (YYYY-MM-DD) in: query name: start_date type: string - description: End date (YYYY-MM-DD) in: query name: end_date type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: stats: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get audit statistics tags: - Audit /auth/2fa/disable: post: consumes: - application/json description: Disable 2FA for user (requires password confirmation) parameters: - description: Password Confirmation in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.DisableTwoFactorRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid password or 2FA not enabled schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Disable 2FA tags: - Auth /auth/2fa/setup: post: consumes: - application/json description: Generate 2FA secret and QR code for setup produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: $ref: '#/definitions/internal_handlers.SetupTwoFactorResponse' type: object "400": description: 2FA already enabled schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Setup 2FA tags: - Auth /auth/2fa/status: get: consumes: - application/json description: Get 2FA enabled status for authenticated user produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: enabled: type: boolean type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get 2FA Status tags: - Auth /auth/2fa/verify: post: consumes: - application/json description: Verify 2FA code and enable 2FA for user parameters: - description: 2FA Code in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.VerifyTwoFactorRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid code schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Verify and Enable 2FA tags: - Auth /auth/check-username: get: consumes: - application/json description: Check if a username is already taken parameters: - description: Username to check in: query name: username required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: available: type: boolean username: type: string type: object type: object "400": description: Missing Username schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Check Username Availability tags: - Auth /auth/login: post: consumes: - application/json description: Authenticate user and return access token. Refresh token is set in httpOnly cookie. parameters: - description: Login Credentials in: body name: request required: true schema: $ref: '#/definitions/veza-backend-api_internal_dto.LoginRequest' produces: - application/json responses: "200": description: Access token returned in body, refresh token in httpOnly cookie schema: $ref: '#/definitions/veza-backend-api_internal_dto.LoginResponse' "400": description: Validation or Bad Request schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Invalid credentials schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: User Login tags: - Auth /auth/logout: post: consumes: - application/json description: Revoke refresh token and current session parameters: - description: Refresh Token to revoke in: body name: request required: true schema: properties: refresh_token: type: string type: object produces: - application/json responses: "200": description: Success message schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Logout tags: - Auth /auth/me: get: consumes: - application/json description: Get profile information of the currently logged-in user produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: User not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Current User tags: - Auth /auth/password/reset: post: consumes: - application/json description: Completes a password reset using a valid token previously emailed to the user. Invalidates all the user's existing sessions on success. parameters: - description: Reset token + new password in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.ResetPasswordRequest' produces: - application/json responses: "200": description: Password reset successfully schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid or expired token, or password validation failed schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Failed to update password schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Reset password with token tags: - Auth /auth/password/reset-request: post: consumes: - application/json description: Sends a password reset link to the user's email if the address exists. Always returns 200 with a generic message to prevent email enumeration. parameters: - description: Email of the account to reset in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.RequestPasswordResetRequest' produces: - application/json responses: "200": description: If the email exists, a reset link has been sent schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Token generation/storage failed (or SMTP failure in production) schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Request password reset tags: - Auth /auth/refresh: post: consumes: - application/json description: Get a new access token using a refresh token parameters: - description: Refresh Token in: body name: request required: true schema: $ref: '#/definitions/veza-backend-api_internal_dto.RefreshRequest' produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/veza-backend-api_internal_dto.TokenResponse' "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Invalid/Expired Refresh Token schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Refresh Token tags: - Auth /auth/register: post: consumes: - application/json description: Register a new user account parameters: - description: Registration Data in: body name: request required: true schema: $ref: '#/definitions/veza-backend-api_internal_dto.RegisterRequest' produces: - application/json responses: "201": description: Created schema: $ref: '#/definitions/veza-backend-api_internal_dto.RegisterResponse' "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "409": description: User already exists schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: User Registration tags: - Auth /auth/resend-verification: post: consumes: - application/json description: Resend the email verification link parameters: - description: Email in: body name: request required: true schema: $ref: '#/definitions/veza-backend-api_internal_dto.ResendVerificationRequest' produces: - application/json responses: "200": description: Success message schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Resend Verification Email tags: - Auth /auth/stream-token: post: description: Returns a 5-minute JWT for HLS and WebSocket authentication (httpOnly cookies prevent direct token access) responses: "200": description: OK schema: $ref: '#/definitions/internal_handlers.StreamTokenResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get ephemeral stream token tags: - Auth /auth/verify-email: post: consumes: - application/json description: |- Verify user email address using a token. v1.0.9 item 1.3: the token is read from the X-Verify-Token header (anti-leak via Referer / proxy access logs). The query-param form remains accepted for backward compatibility with emails sent before v1.0.9 — both paths log a deprecation warning when the query path is used. parameters: - description: Verification Token (preferred) in: header name: X-Verify-Token required: true type: string - description: Verification Token (deprecated, accepted for backward compat) in: query name: token type: string produces: - application/json responses: "200": description: Success message schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Invalid Token schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Verify Email tags: - Auth /chat/token: get: consumes: - application/json description: Generate a short-lived token for chat authentication produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: token: type: string type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Chat Token tags: - Chat /comments/{id}: put: consumes: - application/json description: Update a comment (only by owner) parameters: - description: Comment ID (UUID) in: path name: id required: true type: string - description: Updated comment content in: body name: comment required: true schema: $ref: '#/definitions/internal_handlers.UpdateCommentRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: comment: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden - can only edit own comments schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Comment not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Update comment tags: - Comment /comments/{id}/replies: get: consumes: - application/json description: Get paginated list of replies to a comment parameters: - description: Parent Comment ID (UUID) in: path name: id required: true type: string - default: 1 description: Page number in: query minimum: 1 name: page type: integer - default: 20 description: Items per page in: query maximum: 100 minimum: 1 name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: pagination: type: object replies: type: array type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Parent comment not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get comment replies tags: - Comment /internal/tracks/{id}/stream-ready: post: consumes: - application/json description: Internal endpoint called by the Rust stream server when HLS transcoding completes or fails. Updates the track's stream_status and stream_manifest_url. Requires internal API key (not user-facing). parameters: - description: Track UUID in: path name: id required: true type: string - description: Callback payload in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.StreamCallbackRequest' produces: - application/json responses: "200": description: OK schema: properties: message: type: string type: object "400": description: Validation / invalid id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Stream server callback tags: - Track /playlists: get: consumes: - application/json description: Get a paginated list of playlists parameters: - default: 1 description: Page number in: query name: page type: integer - default: 20 description: Items per page in: query name: limit type: integer - description: Filter by User ID in: query name: user_id type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: pagination: type: object playlists: items: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: array type: object type: object "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Playlists tags: - Playlist post: consumes: - application/json description: Create a new playlist parameters: - description: Playlist Metadata in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.CreatePlaylistRequest' produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Create Playlist tags: - Playlist /playlists/{id}: delete: consumes: - application/json description: Permanently delete a playlist parameters: - description: Playlist ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Delete Playlist tags: - Playlist get: consumes: - application/json description: Get detailed information about a playlist parameters: - description: Playlist ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Invalid ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Playlist by ID tags: - Playlist put: consumes: - application/json description: Update playlist metadata parameters: - description: Playlist ID in: path name: id required: true type: string - description: Playlist Metadata in: body name: playlist required: true schema: $ref: '#/definitions/internal_handlers.UpdatePlaylistRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Update Playlist tags: - Playlist /playlists/{id}/analytics: get: description: Returns aggregated stats for a playlist (plays, follows, tracks count, etc.). Visible to the owner, collaborators and admins. parameters: - description: Playlist UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: stats: type: object type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get playlist statistics tags: - Playlist /playlists/{id}/collaborators: get: description: Returns the collaborators of a playlist with their permission level. parameters: - description: Playlist UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: collaborators: items: type: object type: array type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: List playlist collaborators tags: - Playlist post: consumes: - application/json description: Invite a user as collaborator. Only the owner (or admin) can add. parameters: - description: Playlist UUID in: path name: id required: true type: string - description: Collaborator + permission in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.AddCollaboratorRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: collaborator: type: object type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Add playlist collaborator tags: - Playlist /playlists/{id}/collaborators/{userId}: delete: description: Revoke a collaborator's access. Only the owner (or admin) can remove. parameters: - description: Playlist UUID in: path name: id required: true type: string - description: Collaborator user UUID in: path name: userId required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist or collaborator not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Remove playlist collaborator tags: - Playlist put: consumes: - application/json description: Change a collaborator's permission level (read / write / admin). Only the owner can update. parameters: - description: Playlist UUID in: path name: id required: true type: string - description: Collaborator user UUID in: path name: userId required: true type: string - description: New permission in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.UpdateCollaboratorPermissionRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: collaborator: type: object type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist or collaborator not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Update collaborator permission tags: - Playlist /playlists/{id}/duplicate: post: description: Copy a playlist's track list into a new playlist owned by the authenticated user. Cover/description copied; original unchanged. parameters: - description: Source playlist UUID in: path name: id required: true type: string produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Source not visible schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Source playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Duplicate playlist tags: - Playlist /playlists/{id}/share: post: description: Generate a tokenised link to share a playlist (read-only). Only owner / admin can issue. No body required. parameters: - description: Playlist UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: share: type: object type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Create playlist share link tags: - Playlist /playlists/{id}/tracks: post: consumes: - application/json description: Add a track to the playlist parameters: - description: Playlist ID in: path name: id required: true type: string - description: Track ID (in body) in: body name: trackId required: true schema: properties: track_id: type: string type: object produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Track already present or invalid ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Playlist or Track not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Add Track to Playlist tags: - Playlist /playlists/{id}/tracks/{trackId}: delete: consumes: - application/json description: Remove a track from the playlist parameters: - description: Playlist ID in: path name: id required: true type: string - description: Track ID in: path name: trackId required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "404": description: Playlist or Track not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Remove Track from Playlist tags: - Playlist /playlists/{id}/tracks/reorder: put: consumes: - application/json description: Reorder tracks in the playlist parameters: - description: Playlist ID in: path name: id required: true type: string - description: New Track Order in: body name: order required: true schema: $ref: '#/definitions/internal_handlers.ReorderTracksRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Reorder Tracks tags: - Playlist /playlists/favoris: get: description: Returns the authenticated user's "Favoris" playlist. Auto-created on first call. Used by the like-as-save pattern. produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get Favoris playlist tags: - Playlist /playlists/import: post: consumes: - application/json description: Create a playlist from a JSON payload (title, description, is_public, ordered track IDs). Useful for bulk seed / migration. parameters: - description: Playlist + tracks in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.ImportPlaylistRequest' produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Import playlist tags: - Playlist /playlists/recommendations: get: description: Suggested playlists for the authenticated user. Chronological / declarative discovery — no behavioural ranking (CLAUDE.md rule 7). parameters: - default: 20 description: Max items (max 100) in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlists: items: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: array type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get playlist recommendations tags: - Playlist /playlists/search: get: description: Full-text search on public playlists (title + description). Paginated. parameters: - description: Full-text query in: query name: q type: string - default: 1 description: Page number in: query name: page type: integer - default: 20 description: Items per page (max 100) in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: pagination: type: object playlists: items: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: array type: object type: object "400": description: Validation schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Search playlists tags: - Playlist /playlists/shared/{token}: get: description: Public endpoint resolving a share token. Allows unauthenticated access to the playlist snapshot + tracks. parameters: - description: Share token in: path name: token required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: playlist: $ref: '#/definitions/veza-backend-api_internal_models.Playlist' type: object type: object "400": description: Missing token schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Share expired schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Share or playlist not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get playlist by share token tags: - Playlist /queue: delete: consumes: - application/json description: Removes every item from the authenticated user's playback queue produces: - application/json responses: "200": description: Queue cleared schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Clear queue tags: - Queue get: consumes: - application/json description: Returns the authenticated user's persistent playback queue with all items in position order produces: - application/json responses: "200": description: Queue + items schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: items: items: type: object type: array queue: type: object type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get user playback queue tags: - Queue put: consumes: - application/json description: Updates the authenticated user's queue state (current track / position / playback flags / item order) parameters: - description: Queue update payload in: body name: request required: true schema: $ref: '#/definitions/veza-backend-api_internal_services.UpdateQueueRequest' produces: - application/json responses: "200": description: Updated queue schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: items: items: type: object type: array queue: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Update user playback queue tags: - Queue /queue/items: post: consumes: - application/json description: Appends a track to the authenticated user's playback queue parameters: - description: Track to enqueue in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.AddQueueItemRequest' produces: - application/json responses: "201": description: Created queue item schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: item: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Add track to queue tags: - Queue /queue/items/{id}: delete: consumes: - application/json description: Removes a single item from the authenticated user's playback queue by item ID parameters: - description: Queue item ID (UUID) in: path name: id required: true type: string produces: - application/json responses: "200": description: Item removed schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid item ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Queue item not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Remove queue item tags: - Queue /queue/session: post: consumes: - application/json description: Creates a shared queue session and returns its share token + URL. The session creator is recorded as host. produces: - application/json responses: "201": description: Created session schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: session: type: object share_token: type: string share_url: type: string type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Create collaborative queue session tags: - Queue /queue/session/{token}: delete: consumes: - application/json description: Deletes a collaborative queue session. Only the original session creator can delete. parameters: - description: Session share token in: path name: token required: true type: string produces: - application/json responses: "200": description: Session deleted schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Token required schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Only the creator can delete this session schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Session not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Delete queue session tags: - Queue get: consumes: - application/json description: Returns the session metadata + items for a given share token. No auth required (public — anyone with the link can join). parameters: - description: Session share token in: path name: token required: true type: string produces: - application/json responses: "200": description: Session and queue items schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: items: items: type: object type: array session: type: object type: object type: object "400": description: Token required schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Session not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get queue session by share token tags: - Queue /queue/session/{token}/items: post: consumes: - application/json description: Adds a track to a collaborative queue session. Anyone with the share token can add. parameters: - description: Session share token in: path name: token required: true type: string - description: Track to enqueue in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.AddToSessionRequest' produces: - application/json responses: "201": description: Updated session and items schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: items: items: type: object type: array session: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Session not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Add track to queue session tags: - Queue /queue/session/{token}/items/{id}: delete: consumes: - application/json description: Removes an item from a collaborative queue session by item ID parameters: - description: Session share token in: path name: token required: true type: string - description: Queue item ID (UUID) in: path name: id required: true type: string produces: - application/json responses: "200": description: Item removed schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Session or item not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Remove item from queue session tags: - Queue /search: get: description: Postgres FTS-backed search across tracks, users, and playlists. Optional `type` filter accepts repeated values (e.g., ?type=track&type=user). v1.0.9 item 1.6 — annotation added so orval can generate a typed client. parameters: - description: Search query in: query name: q required: true type: string - collectionFormat: multi description: 'Restrict to one or more entity types: track, user, playlist' in: query items: type: string name: type type: array - description: Opaque pagination cursor in: query name: cursor type: string - description: Page size (max 50) in: query name: limit type: integer produces: - application/json responses: "200": description: Search results schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Search failed schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Unified search tags: - Search /search/suggestions: get: description: Lightweight autocomplete used by the search bar. Returns a small SearchResult subset (typically tracks + users + playlists), capped at `limit` (1..20, default 5). v1.0.9 item 1.6 — annotation added so orval can generate a typed client. parameters: - description: Partial query (min 1 char) in: query name: q required: true type: string - description: Max number of suggestions (1..20, default 5) in: query name: limit type: integer produces: - application/json responses: "200": description: Suggestions schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Suggestions failed schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Search suggestions tags: - Search /social/trending: get: description: Returns the top hashtags surfacing in posts published recently. Counts are aggregated, not user-personalised — discovery is by declarative tags, not behavioural ranking (cf. CLAUDE.md rule 7). v1.0.9 item 1.6 — annotation added so orval can generate a typed client. parameters: - description: Max tags to return (1..50, default 10) in: query name: limit type: integer produces: - application/json responses: "200": description: Trending tags schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Failed to compute trending schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Trending hashtags tags: - Social /tracks: get: description: List tracks with pagination, filters, sort. Cursor-based when ?cursor provided, otherwise page/limit offset. parameters: - description: Opaque pagination cursor (overrides page) in: query name: cursor type: string - default: 1 description: Page number, 1-based (ignored if cursor set) in: query name: page type: integer - default: 20 description: Items per page (max 100) in: query name: limit type: integer - description: Filter by creator UUID in: query name: user_id type: string - description: Filter by genre in: query name: genre type: string - description: Filter by audio format (mp3, flac, wav, ogg, m4a, aac) in: query name: format type: string - default: created_at description: Sort column (created_at, play_count, title) in: query name: sort_by type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: pagination: type: object tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: array type: object type: object "400": description: Invalid query params schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' summary: List tracks tags: - Track post: consumes: - multipart/form-data description: Upload a new track (audio file) parameters: - description: Audio File (MP3, WAV, FLAC, OGG) in: formData name: file required: true type: file produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: track: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: object type: object "400": description: No file or validation error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Quota exceeded schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Upload Track tags: - Track /tracks/{id}: delete: description: Soft-delete a track (sets deleted_at). Caller must own the track or be admin. parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Not owner / no admin schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Delete track tags: - Track get: description: Retrieve a single track. Private play_count / like_count are omitted for non-owners (v0.10.3 F202). parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: track: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' summary: Get track by ID tags: - Track put: consumes: - application/json description: Update the metadata of an existing track. Caller must own the track or be admin. parameters: - description: Track UUID in: path name: id required: true type: string - description: Updated metadata in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.UpdateTrackRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: track: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: object type: object "400": description: Validation / invalid id schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Not owner / no admin schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Update track metadata tags: - Track /tracks/{id}/comments: get: consumes: - application/json description: Get paginated list of comments for a track parameters: - description: Track ID in: path name: id required: true type: string - default: 1 description: Page number in: query name: page type: integer - default: 20 description: Items per page in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: comments: type: array pagination: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get track comments tags: - Comment post: consumes: - application/json description: Create a new comment on a track. Can be a top-level comment or a reply to another comment (using parent_id). parameters: - description: Track ID (UUID) in: path name: id required: true type: string - description: Comment data in: body name: comment required: true schema: $ref: '#/definitions/internal_handlers.CreateCommentRequest' produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: comment: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Create comment tags: - Comment /tracks/{id}/comments/{comment_id}: delete: consumes: - application/json description: Delete a comment (only by owner or admin) parameters: - description: Track ID in: path name: id required: true type: string - description: Comment ID in: path name: comment_id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden - not comment owner schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Comment not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Delete comment tags: - Comment /tracks/{id}/download: get: description: Serve the original audio file. For S3-backed tracks returns a 302 redirect to a signed URL (TTL 30min). For local-backed tracks streams the file with Range support. Public tracks or share_token access; paid tracks require a license. parameters: - description: Track UUID in: path name: id required: true type: string - description: Grants access without authentication for a limited time in: query name: share_token type: string produces: - application/octet-stream responses: "200": description: OK schema: type: file "302": description: Location header points to signed S3 URL (s3-backed tracks) schema: type: string "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: No permission / license required schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track or file not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Download a track tags: - Track /tracks/{id}/history: get: description: Paginated audit log of modifications (metadata updates, version changes) for a track. parameters: - description: Track UUID in: path name: id required: true type: string - default: 50 description: Items per page in: query name: limit type: integer - default: 0 description: Offset in: query name: offset type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: history: items: type: object type: array limit: type: integer offset: type: integer total: type: integer type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Get track history tags: - Track /tracks/{id}/like: delete: description: Remove the authenticated user's like on the track (idempotent). parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Unlike a track tags: - Track post: description: Record a like from the authenticated user. Creates a grouped notification for the creator (F554). parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Like a track tags: - Track /tracks/{id}/likes: get: description: Returns whether the current user has liked the track. The total like count is returned ONLY to the creator or an admin (privacy per ORIGIN_UI_UX_SYSTEM §13). parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: count is omitted for non-owners schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: count: type: integer is_liked: type: boolean type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get track like status tags: - Track /tracks/{id}/lyrics: get: description: Returns the current lyrics for a track, or null if no lyrics exist. parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: lyrics may be null schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: lyrics: type: object type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' summary: Get track lyrics tags: - Track put: consumes: - application/json description: Replace the lyrics of a track. Caller must own the track or be admin. parameters: - description: Track UUID in: path name: id required: true type: string - description: Lyrics payload in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.UpdateLyricsRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: lyrics: type: object type: object type: object "400": description: Validation / invalid id schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Not owner / no admin schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Create or update track lyrics tags: - Track /tracks/{id}/play: post: consumes: - application/json description: Persist a playback event with optional play_time so the creator's analytics dashboard tracks listening behaviour. parameters: - description: Track UUID in: path name: id required: true type: string - description: Playback metadata (optional) in: body name: request schema: $ref: '#/definitions/internal_core_track.RecordPlayRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: id: type: string message: type: string type: object type: object "400": description: Invalid track id / body schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Record play event tags: - Track /tracks/{id}/repost: delete: description: Remove the authenticated user's repost of the track (idempotent). parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Remove track repost tags: - Track get: description: Returns whether the current user has reposted the track. Public (optional auth); unauthenticated callers get is_reposted=false. parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: is_reposted: type: boolean type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Get repost status tags: - Track post: description: Add a track to the authenticated user's profile as a repost. Notifies the creator (F204) unless self-repost. parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Repost a track tags: - Track /tracks/{id}/share: post: consumes: - application/json description: Generate a tokenized share link for a track with given permission level and optional expiry. parameters: - description: Track UUID in: path name: id required: true type: string - description: Share parameters in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.CreateShareRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: share: type: object type: object type: object "400": description: Validation schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Create share link tags: - Track /tracks/{id}/stats: get: description: 'Aggregated track stats: views, likes, comments, play time, downloads, average duration.' parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: stats: type: object type: object type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Get track statistics tags: - Track /tracks/{id}/status: get: consumes: - application/json description: Get the processing status of an uploaded track parameters: - description: Track ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: progress: type: integer type: object type: object "400": description: Invalid ID schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "404": description: Track not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Get Upload Status tags: - Track /tracks/{id}/stream: get: description: Default playback path. S3-backed tracks return a 302 redirect to a signed URL (TTL 15min). Local-backed tracks are streamed via http.ServeContent with Range support. Always available, unlike /hls/* which is gated by HLSEnabled. parameters: - description: Track UUID in: path name: id required: true type: string - description: Grants access without authentication in: query name: share_token type: string produces: - audio/* responses: "200": description: OK schema: type: file "302": description: Location header points to signed S3 URL (s3-backed tracks) schema: type: string "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: No permission schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track or file not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Stream a track (raw audio + Range) tags: - Track /tracks/{id}/versions/{versionId}/restore: post: description: Rollback a track to a previous version. Only the track owner can restore. parameters: - description: Track UUID in: path name: id required: true type: string - description: Version UUID in: path name: versionId required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: Not owner schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Track or version not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Restore track version tags: - Track /tracks/{id}/waveform: get: description: Returns a JSON peaks array used by the client to draw the audio waveform preview. 404 if waveform extraction is not complete yet. parameters: - description: Track UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: Waveform peaks JSON (tool-specific shape) schema: type: object "400": description: Invalid track id schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Waveform not generated / track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Get track waveform tags: - Track /tracks/batch/delete: post: consumes: - application/json description: Soft-delete up to N tracks in one request. Per-track ownership checked (admin can delete others). parameters: - description: List of track UUIDs in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.BatchDeleteRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: deleted: items: type: string type: array failed: items: type: object type: array type: object type: object "400": description: Validation / batch size exceeded schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Batch delete tracks tags: - Track /tracks/batch/update: post: consumes: - application/json description: Apply a partial metadata update to up to N tracks in one request. Per-track ownership checked. parameters: - description: Track UUIDs + shared updates map in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.BatchUpdateRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: failed: items: type: object type: array updated: items: type: string type: array type: object type: object "400": description: Validation / batch size exceeded schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Batch update tracks tags: - Track /tracks/chunk: post: consumes: - multipart/form-data description: Upload a single chunk of a file parameters: - description: Chunk Data in: formData name: chunk required: true type: file - description: Upload ID in: formData name: upload_id required: true type: string - description: Chunk Number in: formData name: chunk_number required: true type: integer - description: Total Chunks in: formData name: total_chunks required: true type: integer - description: Total Size format: int64 in: formData name: total_size required: true type: integer - description: Filename in: formData name: filename required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: message: type: string progress: format: float64 type: number received_chunks: type: integer upload_id: type: string type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Upload Chunk tags: - Track /tracks/complete: post: consumes: - application/json description: Finish upload session and assemble file parameters: - description: Upload ID in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.CompleteChunkedUploadRequest' produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: md5: type: string message: type: string track: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: object type: object "400": description: Validation or Assemblage Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Complete Chunked Upload tags: - Track /tracks/initiate: post: consumes: - application/json description: Start a new chunked upload session parameters: - description: Upload Metadata in: body name: request required: true schema: $ref: '#/definitions/internal_core_track.InitiateChunkedUploadRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: message: type: string upload_id: type: string type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Initiate Chunked Upload tags: - Track /tracks/quota/{id}: get: consumes: - application/json description: Get remaining upload quota for the user parameters: - description: User ID or 'me' for current user in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: quota: type: object type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Get Upload Quota tags: - Track /tracks/recommendations: get: description: Personalized tracks for D2 autoplay. If seed_track_id is given, returns tracks similar to that seed. Otherwise, uses the caller's history (chronological, no behavioural ranking — CLAUDE.md rule 7). parameters: - default: 20 description: Max items (max 100) in: query name: limit type: integer - description: Start from this track's similarity neighbours in: query name: seed_track_id type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: array type: object type: object "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Get track recommendations tags: - Track /tracks/resume/{uploadId}: get: consumes: - application/json description: Get state of an interrupted upload parameters: - description: Upload ID in: path name: uploadId required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: chunks_received: type: integer upload_id: type: string type: object type: object "404": description: Upload session not found schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' security: - BearerAuth: [] summary: Resume Upload tags: - Track /tracks/search: get: description: Full-text + faceted search on tracks (genre, BPM, duration, tags, musical key, dates). Sort-by and order configurable. parameters: - description: Full-text query (title/artist/album) in: query name: q type: string - description: Comma-separated tag list in: query name: tags type: string - default: OR description: Tag combinator (OR / AND) in: query name: tag_mode type: string - description: Minimum duration (seconds) in: query name: min_duration type: integer - description: Maximum duration (seconds) in: query name: max_duration type: integer - description: Minimum BPM in: query name: min_bpm type: integer - description: Maximum BPM in: query name: max_bpm type: integer - description: Genre filter in: query name: genre type: string - description: Audio format filter in: query name: format type: string - description: Musical key filter in: query name: musical_key type: string - description: Created-after (RFC3339) in: query name: min_date type: string - description: Created-before (RFC3339) in: query name: max_date type: string - default: 1 description: Page (1-based) in: query name: page type: integer - default: 20 description: Items per page (max 100) in: query name: limit type: integer - default: created_at description: Sort column in: query name: sort_by type: string - default: desc description: asc / desc in: query name: sort_order type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: pagination: type: object tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: array type: object type: object "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' summary: Advanced track search tags: - Track /tracks/share/{id}: delete: description: Permanently disable a share token. Only the share issuer (or admin) can revoke. parameters: - description: Share UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: Not issuer schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Share not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: Revoke share link tags: - Track /tracks/shared/{token}: get: description: Public endpoint that resolves a share token and returns the track + share metadata. No auth required; the token IS the auth. parameters: - description: Opaque share token issued by CreateShare in: path name: token required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: share: type: object track: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: object type: object "400": description: Missing token schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "403": description: Share link expired schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "404": description: Share or track not found schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: Get track by share token tags: - Track /tracks/suggested-tags: get: description: Returns a static tag suggestion list for a genre — useful for upload autocomplete and filter chips. parameters: - default: default description: Genre slug (pop, rock, electronic, hip-hop, jazz, classical, ambient, default) in: query name: genre type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_response.APIResponse' - properties: data: properties: tags: items: type: string type: array type: object type: object summary: Get suggested tags tags: - Track /users: get: consumes: - application/json description: Get a paginated list of users with optional filtering parameters: - default: 1 description: Page number in: query name: page type: integer - default: 20 description: Items per page in: query name: limit type: integer - description: Filter by role in: query name: role type: string - description: Filter by active status in: query name: is_active type: boolean - description: Filter by verified status in: query name: is_verified type: boolean - description: Search by username, email, first_name, last_name in: query name: search type: string - default: created_at description: Sort field (created_at, username, email, last_login_at) in: query name: sort_by type: string - default: desc description: Sort order (asc, desc) in: query name: sort_order type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: pagination: type: object users: type: array type: object type: object "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: List Users tags: - User /users/{id}: delete: consumes: - application/json description: Soft delete a user (only user owner or admin can delete) parameters: - description: User ID in: path name: id required: true type: string produces: - application/json responses: "200": description: User deleted successfully schema: $ref: '#/definitions/internal_handlers.APIResponse' "400": description: Invalid ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden - Not user owner or admin schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: User not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Delete user tags: - User get: consumes: - application/json description: Get public profile information for a user parameters: - description: User ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: profile: type: object type: object type: object "400": description: Invalid ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: User not found schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get Profile by ID tags: - User put: consumes: - application/json description: Update user profile details parameters: - description: User ID in: path name: id required: true type: string - description: Profile Data in: body name: profile required: true schema: $ref: '#/definitions/internal_handlers.UpdateProfileRequest' produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: profile: type: object type: object type: object "400": description: Validation Error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Update Profile tags: - User /users/{id}/block: delete: description: Authenticated user unblocks target user (idempotent). parameters: - description: Target user UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Unblock user tags: - User post: description: Authenticated user blocks target user (hides their content, prevents follows). Cannot self-block. parameters: - description: Target user UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Validation / self-block schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Block user tags: - User /users/{id}/completion: get: consumes: - application/json description: Get profile completion percentage and missing fields parameters: - description: User ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: type: object type: object "400": description: Invalid ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "403": description: Forbidden schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get Profile Completion tags: - User /users/{id}/follow: delete: description: Authenticated user stops following target user (idempotent). parameters: - description: Target user UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Unfollow user tags: - User post: description: Authenticated user follows target user. Creates a notification (F554 grouped) for the target. parameters: - description: Target user UUID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid id schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: User not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Follow user tags: - User /users/{id}/likes: get: description: Returns paginated tracks the given user has liked. Used for profile "Likes" tab. parameters: - description: User UUID in: path name: id required: true type: string - default: 20 description: Items per page (max 100) in: query name: limit type: integer - default: 0 description: Offset for pagination in: query name: offset type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: limit: type: integer offset: type: integer total: type: integer tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: array type: object type: object "400": description: Validation schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' security: - BearerAuth: [] summary: List tracks liked by a user tags: - User /users/{id}/reposts: get: description: Returns paginated tracks the user has reposted. Used for profile "Reposts" tab. parameters: - description: User UUID in: path name: id required: true type: string - default: 20 description: Items per page (max 100) in: query name: limit type: integer - default: 0 description: Offset for pagination in: query name: offset type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' - properties: data: properties: limit: type: integer offset: type: integer total: type: integer tracks: items: $ref: '#/definitions/veza-backend-api_internal_models.Track' type: array type: object type: object "400": description: Validation schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/veza-backend-api_internal_handlers.APIResponse' summary: List tracks reposted by a user tags: - User /users/by-username/{username}: get: consumes: - application/json description: Get public profile information for a user by username parameters: - description: Username in: path name: username required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: profile: type: object type: object type: object "400": description: Missing username schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: User not found schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Get Profile by Username tags: - User /users/me: delete: description: Permanently delete user account with anonymization, session revocation, audit log parameters: - description: Password, reason, confirm_text (must be DELETE) in: body name: body required: true schema: $ref: '#/definitions/internal_handlers.DeleteAccountRequest' responses: "200": description: OK schema: additionalProperties: true type: object "400": description: Bad Request schema: additionalProperties: true type: object "401": description: Unauthorized schema: additionalProperties: true type: object "500": description: Internal Server Error schema: additionalProperties: true type: object security: - BearerAuth: [] summary: Delete account tags: - Users /users/me/privacy/opt-out: post: description: Saves the user's Do Not Sell preference (CCPA compliance) responses: "200": description: OK schema: additionalProperties: true type: object "401": description: Unauthorized schema: additionalProperties: true type: object "500": description: Internal Server Error schema: additionalProperties: true type: object security: - BearerAuth: [] summary: CCPA Do Not Sell opt-out tags: - Users /users/search: get: description: Full-text search on users (username, display_name). Paginated. Public. parameters: - description: Full-text query in: query name: q type: string - default: 1 description: Page in: query name: page type: integer - default: 20 description: Items per page (max 100) in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: pagination: type: object users: items: $ref: '#/definitions/veza-backend-api_internal_models.User' type: array type: object type: object "400": description: Validation (bounds) schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Search users tags: - User /users/suggestions: get: description: Returns suggested users to follow for the authenticated user. Declarative discovery — no behavioural scoring (CLAUDE.md rule 7). parameters: - default: 10 description: Max items (max 50) in: query name: limit type: integer produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: users: items: $ref: '#/definitions/veza-backend-api_internal_models.User' type: array type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal Error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get follow suggestions tags: - User /validate: post: consumes: - application/json description: Validates request data against known DTO types without executing the actual operation parameters: - description: Validation request with type and data in: body name: request required: true schema: $ref: '#/definitions/internal_handlers.ValidateRequest' produces: - application/json responses: "200": description: Validation result schema: $ref: '#/definitions/internal_handlers.ValidateResponse' "400": description: Invalid request format schema: $ref: '#/definitions/internal_handlers.APIResponse' summary: Validate request body tags: - Validation /webhooks: get: consumes: - application/json description: Get a list of all webhooks registered by the current user produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: webhooks: type: array type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: List webhooks tags: - Webhook post: consumes: - application/json description: Register a new webhook for receiving events parameters: - description: Webhook registration data in: body name: webhook required: true schema: type: object produces: - application/json responses: "201": description: Created schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: webhook: type: object type: object type: object "400": description: Validation error schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Register webhook tags: - Webhook /webhooks/{id}: delete: consumes: - application/json description: Delete a webhook by ID parameters: - description: Webhook ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid webhook ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Webhook not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Delete webhook tags: - Webhook /webhooks/{id}/regenerate-key: post: consumes: - application/json description: Generate a new API key for a webhook (invalidates the old one) parameters: - description: Webhook ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: api_key: type: string message: type: string type: object type: object "400": description: Invalid webhook ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Webhook not found schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Regenerate webhook API key tags: - Webhook /webhooks/{id}/test: post: consumes: - application/json description: Send a test event to a webhook to verify it's working parameters: - description: Webhook ID in: path name: id required: true type: string produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: message: type: string type: object type: object "400": description: Invalid webhook ID schema: $ref: '#/definitions/internal_handlers.APIResponse' "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "404": description: Webhook not found schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Test webhook tags: - Webhook /webhooks/stats: get: consumes: - application/json description: Get statistics for webhook delivery and performance produces: - application/json responses: "200": description: OK schema: allOf: - $ref: '#/definitions/internal_handlers.APIResponse' - properties: data: properties: stats: type: object type: object type: object "401": description: Unauthorized schema: $ref: '#/definitions/internal_handlers.APIResponse' "500": description: Internal server error schema: $ref: '#/definitions/internal_handlers.APIResponse' security: - BearerAuth: [] summary: Get webhook statistics tags: - Webhook securityDefinitions: ApiKeyAuth: description: 'Developer API key (obtain from Developer Portal). Format: vza_xxxxx' in: header name: X-API-Key type: apiKey BearerAuth: in: header name: Authorization type: apiKey swagger: "2.0"