Closes FUNCTIONAL_AUDIT.md §4 #1: WebRTC 1:1 calls had working signaling but no NAT traversal, so calls between two peers behind symmetric NAT (corporate firewalls, mobile carrier CGNAT, Incus container default networking) failed silently after the SDP exchange. Backend: - GET /api/v1/config/webrtc (public) returns {iceServers: [...]} built from WEBRTC_STUN_URLS / WEBRTC_TURN_URLS / *_USERNAME / *_CREDENTIAL env vars. Half-config (URLs without creds, or vice versa) deliberately omits the TURN block — a half-configured TURN surfaces auth errors at call time instead of falling back cleanly to STUN-only. - 4 handler tests cover the matrix. Frontend: - services/api/webrtcConfig.ts caches the config for the page lifetime and falls back to the historical hardcoded Google STUN if the fetch fails. - useWebRTC fetches at mount, hands iceServers synchronously to every RTCPeerConnection, exposes a {hasTurn, loaded} hint. - CallButton tooltip warns up-front when TURN isn't configured instead of letting calls time out silently. Ops: - infra/coturn/turnserver.conf — annotated template with the SSRF- safe denied-peer-ip ranges, prometheus exporter, TLS for TURNS, static lt-cred-mech (REST-secret rotation deferred to v1.1). - infra/coturn/README.md — Incus deploy walkthrough, smoke test via turnutils_uclient, capacity rules of thumb. - docs/ENV_VARIABLES.md gains a 13bis. WebRTC ICE servers section. Coturn deployment itself is a separate ops action — this commit lands the plumbing so the deploy can light up the path with zero code changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6636 lines
183 KiB
YAML
6636 lines
183 KiB
YAML
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.IceServer:
|
|
properties:
|
|
credential:
|
|
type: string
|
|
urls:
|
|
items:
|
|
type: string
|
|
type: array
|
|
username:
|
|
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
|
|
internal_handlers.WebRTCConfigResponse:
|
|
properties:
|
|
iceServers:
|
|
items:
|
|
$ref: '#/definitions/internal_handlers.IceServer'
|
|
type: array
|
|
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
|
|
/config/webrtc:
|
|
get:
|
|
description: Public — returns the ICE-server set the SPA feeds to RTCPeerConnection.
|
|
STUN-only when no TURN is configured. TURN credentials are always emitted
|
|
as static (REST shared-secret rotation deferred to v1.1).
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: ICE servers
|
|
schema:
|
|
$ref: '#/definitions/internal_handlers.WebRTCConfigResponse'
|
|
summary: WebRTC ICE configuration
|
|
tags:
|
|
- Config
|
|
/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"
|