Two consolidations:
(1) Annotate `/search`, `/search/suggestions`, `/social/trending` with
swag tags so orval generates typed clients for them. Migrate
`searchApi` and `socialApi` (the two remaining hand-written wrappers
in `apps/web/src/services/api/`) to delegate to the generated
functions. Removes the last drift surface where backend changes to
those endpoints could silently mismatch the SPA.
(2) Delete two orphan auth-service implementations that have parallel-
implemented login/register/verifyEmail with stale wire shapes:
- apps/web/src/services/authService.ts (only its own test imports it)
- apps/web/src/features/auth/services/authService.ts (re-exported
from features/auth/index.ts but the barrel itself has zero
importers across the SPA)
The active path remains `services/api/auth.ts` (the integration layer
that owns token storage, csrf, and proactive refresh) — the duplicates
were dead post-v1.0.8 orval migration and silently diverged from the
true backend shape (e.g., the deleted services still expected
`access_token` at the root of the register response, never matched
current backend, broke when v1.0.9 item 1.4 changed the shape).
Net diff: -944 LOC of dead code, +typed orval clients for 2 more
endpoints, zero importer rewires.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10437 lines
No EOL
393 KiB
JSON
10437 lines
No EOL
393 KiB
JSON
{
|
|
"swagger": "2.0",
|
|
"info": {
|
|
"description": "Backend API for Veza platform.",
|
|
"title": "Veza Backend API",
|
|
"termsOfService": "http://swagger.io/terms/",
|
|
"contact": {
|
|
"name": "API Support",
|
|
"url": "http://www.veza.app/support",
|
|
"email": "support@veza.app"
|
|
},
|
|
"license": {
|
|
"name": "Apache 2.0",
|
|
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
},
|
|
"version": "1.2.0"
|
|
},
|
|
"host": "localhost:18080",
|
|
"basePath": "/api/v1",
|
|
"paths": {
|
|
"/api/v1/dashboard": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get aggregated dashboard data including stats, recent activity, and library preview",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Dashboard"
|
|
],
|
|
"summary": "Get Dashboard Data",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"description": "Number of recent activity items (default: 10)",
|
|
"name": "activity_limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Number of library items (default: 5)",
|
|
"name": "library_limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Time period for statistics: 7d, 30d, 90d, all (default: 30d)",
|
|
"name": "stats_period",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"$ref": "#/definitions/internal_handlers.DashboardResponse"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal server error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/logs/frontend": {
|
|
"post": {
|
|
"description": "Receive and store a log entry from the frontend application",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Logging"
|
|
],
|
|
"summary": "Receive frontend log",
|
|
"parameters": [
|
|
{
|
|
"description": "Frontend log entry",
|
|
"name": "log",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.FrontendLogRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"received": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid log entry",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal server error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/marketplace/download/{product_id}": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get a secure download URL for a purchased product",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "Get download URL",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Product ID",
|
|
"name": "product_id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/marketplace/orders": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get all orders for the authenticated user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "List user orders",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.Order"
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Purchase products",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "Create a new order",
|
|
"parameters": [
|
|
{
|
|
"description": "Order items",
|
|
"name": "order",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.CreateOrderRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/marketplace/orders/{id}": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get details of a specific order (only order owner can access)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "Get order details",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Order ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/marketplace/products": {
|
|
"get": {
|
|
"description": "List marketplace products with filters",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "List products",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Product status",
|
|
"name": "status",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Seller ID",
|
|
"name": "seller_id",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Search query",
|
|
"name": "q",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Product type (track, pack, service)",
|
|
"name": "type",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "number",
|
|
"description": "Minimum price",
|
|
"name": "min_price",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "number",
|
|
"description": "Maximum price",
|
|
"name": "max_price",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.Product"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Create a product (Track, Pack, Service) for sale",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "Create a new product",
|
|
"parameters": [
|
|
{
|
|
"description": "Product info",
|
|
"name": "product",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.CreateProductRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/v1/marketplace/products/{id}": {
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Update product details (only seller can update)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Marketplace"
|
|
],
|
|
"summary": "Update a product",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Product ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Product updates",
|
|
"name": "product",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.UpdateProductRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/audit/activity": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get recent activity logs for the current user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Audit"
|
|
],
|
|
"summary": "Get user activity",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 50,
|
|
"description": "Number of activities to return",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"activities": {
|
|
"type": "array"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal server error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/audit/logs": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Search and filter audit logs with pagination support. Supports filtering by action, resource, date range, IP address, and user agent.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Audit"
|
|
],
|
|
"summary": "Search audit logs",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by action type",
|
|
"name": "action",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by resource type",
|
|
"name": "resource",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by resource ID (UUID)",
|
|
"name": "resource_id",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by IP address",
|
|
"name": "ip_address",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by user agent",
|
|
"name": "user_agent",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Start date filter (YYYY-MM-DD)",
|
|
"name": "start_date",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "End date filter (YYYY-MM-DD)",
|
|
"name": "end_date",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Offset for pagination",
|
|
"name": "offset",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"logs": {
|
|
"type": "array"
|
|
},
|
|
"pagination": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/audit/stats": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get audit statistics for the current user, optionally filtered by date range",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Audit"
|
|
],
|
|
"summary": "Get audit statistics",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Start date (YYYY-MM-DD)",
|
|
"name": "start_date",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "End date (YYYY-MM-DD)",
|
|
"name": "end_date",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"stats": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/2fa/disable": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Disable 2FA for user (requires password confirmation)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Disable 2FA",
|
|
"parameters": [
|
|
{
|
|
"description": "Password Confirmation",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.DisableTwoFactorRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/2fa/setup": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Generate 2FA secret and QR code for setup",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Setup 2FA",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"$ref": "#/definitions/internal_handlers.SetupTwoFactorResponse"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/2fa/status": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get 2FA enabled status for authenticated user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Get 2FA Status",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/2fa/verify": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Verify 2FA code and enable 2FA for user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Verify and Enable 2FA",
|
|
"parameters": [
|
|
{
|
|
"description": "2FA Code",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.VerifyTwoFactorRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/check-username": {
|
|
"get": {
|
|
"description": "Check if a username is already taken",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Check Username Availability",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Username to check",
|
|
"name": "username",
|
|
"in": "query",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"available": {
|
|
"type": "boolean"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Missing Username",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/login": {
|
|
"post": {
|
|
"description": "Authenticate user and return access token. Refresh token is set in httpOnly cookie.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "User Login",
|
|
"parameters": [
|
|
{
|
|
"description": "Login Credentials",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.LoginRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/logout": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Revoke refresh token and current session",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Logout",
|
|
"parameters": [
|
|
{
|
|
"description": "Refresh Token to revoke",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"refresh_token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/me": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get profile information of the currently logged-in user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Get Current User",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "User not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/password/reset": {
|
|
"post": {
|
|
"description": "Completes a password reset using a valid token previously emailed to the user. Invalidates all the user's existing sessions on success.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Reset password with token",
|
|
"parameters": [
|
|
{
|
|
"description": "Reset token + new password",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.ResetPasswordRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Password reset successfully",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/password/reset-request": {
|
|
"post": {
|
|
"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.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Request password reset",
|
|
"parameters": [
|
|
{
|
|
"description": "Email of the account to reset",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.RequestPasswordResetRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "If the email exists, a reset link has been sent",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/refresh": {
|
|
"post": {
|
|
"description": "Get a new access token using a refresh token",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Refresh Token",
|
|
"parameters": [
|
|
{
|
|
"description": "Refresh Token",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.RefreshRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/register": {
|
|
"post": {
|
|
"description": "Register a new user account",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "User Registration",
|
|
"parameters": [
|
|
{
|
|
"description": "Registration Data",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.RegisterRequest"
|
|
}
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/resend-verification": {
|
|
"post": {
|
|
"description": "Resend the email verification link",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Resend Verification Email",
|
|
"parameters": [
|
|
{
|
|
"description": "Email",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.ResendVerificationRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Success message",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/stream-token": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns a 5-minute JWT for HLS and WebSocket authentication (httpOnly cookies prevent direct token access)",
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Get ephemeral stream token",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.StreamTokenResponse"
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/auth/verify-email": {
|
|
"post": {
|
|
"description": "Verify user email address using a token. v1.0.9 item 1.3:\nthe token is read from the X-Verify-Token header (anti-leak\nvia Referer / proxy access logs). The query-param form\nremains accepted for backward compatibility with emails sent\nbefore v1.0.9 — both paths log a deprecation warning when\nthe query path is used.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Auth"
|
|
],
|
|
"summary": "Verify Email",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Verification Token (preferred)",
|
|
"name": "X-Verify-Token",
|
|
"in": "header",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Verification Token (deprecated, accepted for backward compat)",
|
|
"name": "token",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Success message",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid Token",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/chat/token": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Generate a short-lived token for chat authentication",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Chat"
|
|
],
|
|
"summary": "Get Chat Token",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/comments/{id}": {
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Update a comment (only by owner)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Comment"
|
|
],
|
|
"summary": "Update comment",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Comment ID (UUID)",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Updated comment content",
|
|
"name": "comment",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.UpdateCommentRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"comment": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/comments/{id}/replies": {
|
|
"get": {
|
|
"description": "Get paginated list of replies to a comment",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Comment"
|
|
],
|
|
"summary": "Get comment replies",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Parent Comment ID (UUID)",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"minimum": 1,
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"maximum": 100,
|
|
"minimum": 1,
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"replies": {
|
|
"type": "array"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/internal/tracks/{id}/stream-ready": {
|
|
"post": {
|
|
"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).",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Stream server callback",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Callback payload",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.StreamCallbackRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get a paginated list of playlists",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get Playlists",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by User ID",
|
|
"name": "user_id",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"playlists": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Create a new playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Create Playlist",
|
|
"parameters": [
|
|
{
|
|
"description": "Playlist Metadata",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.CreatePlaylistRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/favoris": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns the authenticated user's \"Favoris\" playlist. Auto-created on first call. Used by the like-as-save pattern.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get Favoris playlist",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/import": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Create a playlist from a JSON payload (title, description, is_public, ordered track IDs). Useful for bulk seed / migration.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Import playlist",
|
|
"parameters": [
|
|
{
|
|
"description": "Playlist + tracks",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.ImportPlaylistRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/recommendations": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Suggested playlists for the authenticated user. Chronological / declarative discovery — no behavioural ranking (CLAUDE.md rule 7).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get playlist recommendations",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Max items (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlists": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/search": {
|
|
"get": {
|
|
"description": "Full-text search on public playlists (title + description). Paginated.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Search playlists",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Full-text query",
|
|
"name": "q",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"playlists": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/shared/{token}": {
|
|
"get": {
|
|
"description": "Public endpoint resolving a share token. Allows unauthenticated access to the playlist snapshot + tracks.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get playlist by share token",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Share token",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get detailed information about a playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get Playlist by ID",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid ID",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Playlist not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Update playlist metadata",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Update Playlist",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Playlist Metadata",
|
|
"name": "playlist",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.UpdatePlaylistRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Permanently delete a playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Delete Playlist",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/analytics": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns aggregated stats for a playlist (plays, follows, tracks count, etc.). Visible to the owner, collaborators and admins.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Get playlist statistics",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"stats": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/collaborators": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns the collaborators of a playlist with their permission level.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "List playlist collaborators",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"collaborators": {
|
|
"type": "array",
|
|
"items": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Invite a user as collaborator. Only the owner (or admin) can add.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Add playlist collaborator",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Collaborator + permission",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.AddCollaboratorRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"collaborator": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/collaborators/{userId}": {
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Change a collaborator's permission level (read / write / admin). Only the owner can update.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Update collaborator permission",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Collaborator user UUID",
|
|
"name": "userId",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "New permission",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.UpdateCollaboratorPermissionRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"collaborator": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Revoke a collaborator's access. Only the owner (or admin) can remove.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Remove playlist collaborator",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Collaborator user UUID",
|
|
"name": "userId",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/duplicate": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Copy a playlist's track list into a new playlist owned by the authenticated user. Cover/description copied; original unchanged.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Duplicate playlist",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Source playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Playlist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/share": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Generate a tokenised link to share a playlist (read-only). Only owner / admin can issue. No body required.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Create playlist share link",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"share": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/tracks": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Add a track to the playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Add Track to Playlist",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Track ID (in body)",
|
|
"name": "trackId",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"track_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/tracks/reorder": {
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Reorder tracks in the playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Reorder Tracks",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "New Track Order",
|
|
"name": "order",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.ReorderTracksRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/playlists/{id}/tracks/{trackId}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Remove a track from the playlist",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Playlist"
|
|
],
|
|
"summary": "Remove Track from Playlist",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Playlist ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Track ID",
|
|
"name": "trackId",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Playlist or Track not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns the authenticated user's persistent playback queue with all items in position order",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Get user playback queue",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Queue + items",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"queue": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Updates the authenticated user's queue state (current track / position / playback flags / item order)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Update user playback queue",
|
|
"parameters": [
|
|
{
|
|
"description": "Queue update payload",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_services.UpdateQueueRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated queue",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"queue": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Removes every item from the authenticated user's playback queue",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Clear queue",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Queue cleared",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/items": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Appends a track to the authenticated user's playback queue",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Add track to queue",
|
|
"parameters": [
|
|
{
|
|
"description": "Track to enqueue",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.AddQueueItemRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created queue item",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"item": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/items/{id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Removes a single item from the authenticated user's playback queue by item ID",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Remove queue item",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Queue item ID (UUID)",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Item removed",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/session": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Creates a shared queue session and returns its share token + URL. The session creator is recorded as host.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Create collaborative queue session",
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created session",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"session": {
|
|
"type": "object"
|
|
},
|
|
"share_token": {
|
|
"type": "string"
|
|
},
|
|
"share_url": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/session/{token}": {
|
|
"get": {
|
|
"description": "Returns the session metadata + items for a given share token. No auth required (public — anyone with the link can join).",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Get queue session by share token",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Session share token",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Session and queue items",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"session": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Deletes a collaborative queue session. Only the original session creator can delete.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Delete queue session",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Session share token",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Session deleted",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/session/{token}/items": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Adds a track to a collaborative queue session. Anyone with the share token can add.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Add track to queue session",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Session share token",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Track to enqueue",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.AddToSessionRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Updated session and items",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"session": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/queue/session/{token}/items/{id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Removes an item from a collaborative queue session by item ID",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Queue"
|
|
],
|
|
"summary": "Remove item from queue session",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Session share token",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Queue item ID (UUID)",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Item removed",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/search": {
|
|
"get": {
|
|
"description": "Postgres FTS-backed search across tracks, users, and playlists. Optional `type` filter accepts repeated values (e.g., ?type=track\u0026type=user). v1.0.9 item 1.6 — annotation added so orval can generate a typed client.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Search"
|
|
],
|
|
"summary": "Unified search",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Search query",
|
|
"name": "q",
|
|
"in": "query",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"collectionFormat": "multi",
|
|
"description": "Restrict to one or more entity types: track, user, playlist",
|
|
"name": "type",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Opaque pagination cursor",
|
|
"name": "cursor",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Page size (max 50)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Search"
|
|
],
|
|
"summary": "Search suggestions",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Partial query (min 1 char)",
|
|
"name": "q",
|
|
"in": "query",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Max number of suggestions (1..20, default 5)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Social"
|
|
],
|
|
"summary": "Trending hashtags",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"description": "Max tags to return (1..50, default 10)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Trending tags",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Failed to compute trending",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks": {
|
|
"get": {
|
|
"description": "List tracks with pagination, filters, sort. Cursor-based when ?cursor provided, otherwise page/limit offset.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "List tracks",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Opaque pagination cursor (overrides page)",
|
|
"name": "cursor",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number, 1-based (ignored if cursor set)",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by creator UUID",
|
|
"name": "user_id",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by genre",
|
|
"name": "genre",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by audio format (mp3, flac, wav, ogg, m4a, aac)",
|
|
"name": "format",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "created_at",
|
|
"description": "Sort column (created_at, play_count, title)",
|
|
"name": "sort_by",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Upload a new track (audio file)",
|
|
"consumes": [
|
|
"multipart/form-data"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Upload Track",
|
|
"parameters": [
|
|
{
|
|
"type": "file",
|
|
"description": "Audio File (MP3, WAV, FLAC, OGG)",
|
|
"name": "file",
|
|
"in": "formData",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"track": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/batch/delete": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Soft-delete up to N tracks in one request. Per-track ownership checked (admin can delete others).",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Batch delete tracks",
|
|
"parameters": [
|
|
{
|
|
"description": "List of track UUIDs",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.BatchDeleteRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"deleted": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"failed": {
|
|
"type": "array",
|
|
"items": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/batch/update": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Apply a partial metadata update to up to N tracks in one request. Per-track ownership checked.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Batch update tracks",
|
|
"parameters": [
|
|
{
|
|
"description": "Track UUIDs + shared updates map",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.BatchUpdateRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"failed": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"updated": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/chunk": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Upload a single chunk of a file",
|
|
"consumes": [
|
|
"multipart/form-data"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Upload Chunk",
|
|
"parameters": [
|
|
{
|
|
"type": "file",
|
|
"description": "Chunk Data",
|
|
"name": "chunk",
|
|
"in": "formData",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Upload ID",
|
|
"name": "upload_id",
|
|
"in": "formData",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Chunk Number",
|
|
"name": "chunk_number",
|
|
"in": "formData",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Total Chunks",
|
|
"name": "total_chunks",
|
|
"in": "formData",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Total Size",
|
|
"name": "total_size",
|
|
"in": "formData",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filename",
|
|
"name": "filename",
|
|
"in": "formData",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"progress": {
|
|
"type": "number",
|
|
"format": "float64"
|
|
},
|
|
"received_chunks": {
|
|
"type": "integer"
|
|
},
|
|
"upload_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/complete": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Finish upload session and assemble file",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Complete Chunked Upload",
|
|
"parameters": [
|
|
{
|
|
"description": "Upload ID",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.CompleteChunkedUploadRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"md5": {
|
|
"type": "string"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"track": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/initiate": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Start a new chunked upload session",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Initiate Chunked Upload",
|
|
"parameters": [
|
|
{
|
|
"description": "Upload Metadata",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.InitiateChunkedUploadRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"upload_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/quota/{id}": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get remaining upload quota for the user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get Upload Quota",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User ID or 'me' for current user",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"quota": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/recommendations": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"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).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track recommendations",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Max items (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Start from this track's similarity neighbours",
|
|
"name": "seed_track_id",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/resume/{uploadId}": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get state of an interrupted upload",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Resume Upload",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Upload ID",
|
|
"name": "uploadId",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"chunks_received": {
|
|
"type": "integer"
|
|
},
|
|
"upload_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Upload session not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/search": {
|
|
"get": {
|
|
"description": "Full-text + faceted search on tracks (genre, BPM, duration, tags, musical key, dates). Sort-by and order configurable.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Advanced track search",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Full-text query (title/artist/album)",
|
|
"name": "q",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Comma-separated tag list",
|
|
"name": "tags",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "OR",
|
|
"description": "Tag combinator (OR / AND)",
|
|
"name": "tag_mode",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Minimum duration (seconds)",
|
|
"name": "min_duration",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Maximum duration (seconds)",
|
|
"name": "max_duration",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Minimum BPM",
|
|
"name": "min_bpm",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"description": "Maximum BPM",
|
|
"name": "max_bpm",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Genre filter",
|
|
"name": "genre",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Audio format filter",
|
|
"name": "format",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Musical key filter",
|
|
"name": "musical_key",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Created-after (RFC3339)",
|
|
"name": "min_date",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Created-before (RFC3339)",
|
|
"name": "max_date",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page (1-based)",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "created_at",
|
|
"description": "Sort column",
|
|
"name": "sort_by",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "desc",
|
|
"description": "asc / desc",
|
|
"name": "sort_order",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/share/{id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Permanently disable a share token. Only the share issuer (or admin) can revoke.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Revoke share link",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Share UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track by share token",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Opaque share token issued by CreateShare",
|
|
"name": "token",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"share": {
|
|
"type": "object"
|
|
},
|
|
"track": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/suggested-tags": {
|
|
"get": {
|
|
"description": "Returns a static tag suggestion list for a genre — useful for upload autocomplete and filter chips.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get suggested tags",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"default": "default",
|
|
"description": "Genre slug (pop, rock, electronic, hip-hop, jazz, classical, ambient, default)",
|
|
"name": "genre",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"tags": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}": {
|
|
"get": {
|
|
"description": "Retrieve a single track. Private play_count / like_count are omitted for non-owners (v0.10.3 F202).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track by ID",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"track": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Update the metadata of an existing track. Caller must own the track or be admin.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Update track metadata",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Updated metadata",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.UpdateTrackRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"track": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Soft-delete a track (sets deleted_at). Caller must own the track or be admin.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Delete track",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/comments": {
|
|
"get": {
|
|
"description": "Get paginated list of comments for a track",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Comment"
|
|
],
|
|
"summary": "Get track comments",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"comments": {
|
|
"type": "array"
|
|
},
|
|
"pagination": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Create a new comment on a track. Can be a top-level comment or a reply to another comment (using parent_id).",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Comment"
|
|
],
|
|
"summary": "Create comment",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track ID (UUID)",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Comment data",
|
|
"name": "comment",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.CreateCommentRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"comment": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/comments/{comment_id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Delete a comment (only by owner or admin)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Comment"
|
|
],
|
|
"summary": "Delete comment",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Comment ID",
|
|
"name": "comment_id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"application/octet-stream"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Download a track",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Grants access without authentication for a limited time",
|
|
"name": "share_token",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/history": {
|
|
"get": {
|
|
"description": "Paginated audit log of modifications (metadata updates, version changes) for a track.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track history",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 50,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 0,
|
|
"description": "Offset",
|
|
"name": "offset",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"history": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"limit": {
|
|
"type": "integer"
|
|
},
|
|
"offset": {
|
|
"type": "integer"
|
|
},
|
|
"total": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/like": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Record a like from the authenticated user. Creates a grouped notification for the creator (F554).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Like a track",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Remove the authenticated user's like on the track (idempotent).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Unlike a track",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/likes": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"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).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track like status",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "count is omitted for non-owners",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"count": {
|
|
"type": "integer"
|
|
},
|
|
"is_liked": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/lyrics": {
|
|
"get": {
|
|
"description": "Returns the current lyrics for a track, or null if no lyrics exist.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track lyrics",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "lyrics may be null",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"lyrics": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Replace the lyrics of a track. Caller must own the track or be admin.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Create or update track lyrics",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Lyrics payload",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.UpdateLyricsRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"lyrics": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/play": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Persist a playback event with optional play_time so the creator's analytics dashboard tracks listening behaviour.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Record play event",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Playback metadata (optional)",
|
|
"name": "request",
|
|
"in": "body",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.RecordPlayRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/repost": {
|
|
"get": {
|
|
"description": "Returns whether the current user has reposted the track. Public (optional auth); unauthenticated callers get is_reposted=false.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get repost status",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"is_reposted": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid track id",
|
|
"schema": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Add a track to the authenticated user's profile as a repost. Notifies the creator (F204) unless self-repost.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Repost a track",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Remove the authenticated user's repost of the track (idempotent).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Remove track repost",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/share": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Generate a tokenized share link for a track with given permission level and optional expiry.",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Create share link",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Share parameters",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_core_track.CreateShareRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"share": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/stats": {
|
|
"get": {
|
|
"description": "Aggregated track stats: views, likes, comments, play time, downloads, average duration.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track statistics",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"stats": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/status": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get the processing status of an uploaded track",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get Upload Status",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"progress": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"audio/*"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Stream a track (raw audio + Range)",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Grants access without authentication",
|
|
"name": "share_token",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/tracks/{id}/versions/{versionId}/restore": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Rollback a track to a previous version. Only the track owner can restore.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Restore track version",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Version UUID",
|
|
"name": "versionId",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/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.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Track"
|
|
],
|
|
"summary": "Get track waveform",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Track UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users": {
|
|
"get": {
|
|
"description": "Get a paginated list of users with optional filtering",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "List Users",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page number",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Filter by role",
|
|
"name": "role",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "boolean",
|
|
"description": "Filter by active status",
|
|
"name": "is_active",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "boolean",
|
|
"description": "Filter by verified status",
|
|
"name": "is_verified",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"description": "Search by username, email, first_name, last_name",
|
|
"name": "search",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "created_at",
|
|
"description": "Sort field (created_at, username, email, last_login_at)",
|
|
"name": "sort_by",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "string",
|
|
"default": "desc",
|
|
"description": "Sort order (asc, desc)",
|
|
"name": "sort_order",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"users": {
|
|
"type": "array"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/by-username/{username}": {
|
|
"get": {
|
|
"description": "Get public profile information for a user by username",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Get Profile by Username",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Username",
|
|
"name": "username",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"profile": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Missing username",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "User not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/me": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Permanently delete user account with anonymization, session revocation, audit log",
|
|
"tags": [
|
|
"Users"
|
|
],
|
|
"summary": "Delete account",
|
|
"parameters": [
|
|
{
|
|
"description": "Password, reason, confirm_text (must be DELETE)",
|
|
"name": "body",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.DeleteAccountRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Bad Request",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Server Error",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/me/privacy/opt-out": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Saves the user's Do Not Sell preference (CCPA compliance)",
|
|
"tags": [
|
|
"Users"
|
|
],
|
|
"summary": "CCPA Do Not Sell opt-out",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Server Error",
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/search": {
|
|
"get": {
|
|
"description": "Full-text search on users (username, display_name). Paginated. Public.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Search users",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Full-text query",
|
|
"name": "q",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 1,
|
|
"description": "Page",
|
|
"name": "page",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pagination": {
|
|
"type": "object"
|
|
},
|
|
"users": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.User"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Validation (bounds)",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/suggestions": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns suggested users to follow for the authenticated user. Declarative discovery — no behavioural scoring (CLAUDE.md rule 7).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Get follow suggestions",
|
|
"parameters": [
|
|
{
|
|
"type": "integer",
|
|
"default": 10,
|
|
"description": "Max items (max 50)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"users": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.User"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal Error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}": {
|
|
"get": {
|
|
"description": "Get public profile information for a user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Get Profile by ID",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"profile": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid ID",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "User not found",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Update user profile details",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Update Profile",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"description": "Profile Data",
|
|
"name": "profile",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.UpdateProfileRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"profile": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Soft delete a user (only user owner or admin can delete)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Delete user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}/block": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Authenticated user blocks target user (hides their content, prevents follows). Cannot self-block.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Block user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Target user UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Authenticated user unblocks target user (idempotent).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Unblock user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Target user UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}/completion": {
|
|
"get": {
|
|
"description": "Get profile completion percentage and missing fields",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Get Profile Completion",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}/follow": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Authenticated user follows target user. Creates a notification (F554 grouped) for the target.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Follow user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Target user UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Authenticated user stops following target user (idempotent).",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "Unfollow user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Target user UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}/likes": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Returns paginated tracks the given user has liked. Used for profile \"Likes\" tab.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "List tracks liked by a user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 0,
|
|
"description": "Offset for pagination",
|
|
"name": "offset",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {
|
|
"type": "integer"
|
|
},
|
|
"offset": {
|
|
"type": "integer"
|
|
},
|
|
"total": {
|
|
"type": "integer"
|
|
},
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/users/{id}/reposts": {
|
|
"get": {
|
|
"description": "Returns paginated tracks the user has reposted. Used for profile \"Reposts\" tab.",
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"User"
|
|
],
|
|
"summary": "List tracks reposted by a user",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "User UUID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 20,
|
|
"description": "Items per page (max 100)",
|
|
"name": "limit",
|
|
"in": "query"
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"default": 0,
|
|
"description": "Offset for pagination",
|
|
"name": "offset",
|
|
"in": "query"
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/veza-backend-api_internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {
|
|
"type": "integer"
|
|
},
|
|
"offset": {
|
|
"type": "integer"
|
|
},
|
|
"total": {
|
|
"type": "integer"
|
|
},
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/validate": {
|
|
"post": {
|
|
"description": "Validates request data against known DTO types without executing the actual operation",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Validation"
|
|
],
|
|
"summary": "Validate request body",
|
|
"parameters": [
|
|
{
|
|
"description": "Validation request with type and data",
|
|
"name": "request",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.ValidateRequest"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Validation result",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.ValidateResponse"
|
|
}
|
|
},
|
|
"400": {
|
|
"description": "Invalid request format",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/webhooks": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get a list of all webhooks registered by the current user",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "List webhooks",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"webhooks": {
|
|
"type": "array"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal server error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Register a new webhook for receiving events",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "Register webhook",
|
|
"parameters": [
|
|
{
|
|
"description": "Webhook registration data",
|
|
"name": "webhook",
|
|
"in": "body",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"webhook": {
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/webhooks/stats": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Get statistics for webhook delivery and performance",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "Get webhook statistics",
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"stats": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "Unauthorized",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "Internal server error",
|
|
"schema": {
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/webhooks/{id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Delete a webhook by ID",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "Delete webhook",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Webhook ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/webhooks/{id}/regenerate-key": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Generate a new API key for a webhook (invalidates the old one)",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "Regenerate webhook API key",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Webhook ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"api_key": {
|
|
"type": "string"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/webhooks/{id}/test": {
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"BearerAuth": []
|
|
}
|
|
],
|
|
"description": "Send a test event to a webhook to verify it's working",
|
|
"consumes": [
|
|
"application/json"
|
|
],
|
|
"produces": [
|
|
"application/json"
|
|
],
|
|
"tags": [
|
|
"Webhook"
|
|
],
|
|
"summary": "Test webhook",
|
|
"parameters": [
|
|
{
|
|
"type": "string",
|
|
"description": "Webhook ID",
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "OK",
|
|
"schema": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/definitions/internal_handlers.APIResponse"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"definitions": {
|
|
"internal_core_track.BatchDeleteRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"track_ids"
|
|
],
|
|
"properties": {
|
|
"track_ids": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.BatchUpdateRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"track_ids",
|
|
"updates"
|
|
],
|
|
"properties": {
|
|
"track_ids": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"updates": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.CompleteChunkedUploadRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"upload_id"
|
|
],
|
|
"properties": {
|
|
"upload_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.CreateShareRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"permissions"
|
|
],
|
|
"properties": {
|
|
"expires_at": {
|
|
"type": "string"
|
|
},
|
|
"permissions": {
|
|
"type": "string",
|
|
"enum": [
|
|
"read",
|
|
"write",
|
|
"admin"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.InitiateChunkedUploadRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"filename",
|
|
"total_chunks",
|
|
"total_size"
|
|
],
|
|
"properties": {
|
|
"filename": {
|
|
"type": "string"
|
|
},
|
|
"total_chunks": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"total_size": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.RecordPlayRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"play_time": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.StreamCallbackRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"status"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string"
|
|
},
|
|
"manifest_url": {
|
|
"type": "string"
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"enum": [
|
|
"completed",
|
|
"failed",
|
|
"processing"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.UpdateLyricsRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"content": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_core_track.UpdateTrackRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"album": {
|
|
"type": "string",
|
|
"maxLength": 255
|
|
},
|
|
"artist": {
|
|
"type": "string",
|
|
"maxLength": 255
|
|
},
|
|
"bpm": {
|
|
"type": "integer",
|
|
"maximum": 300,
|
|
"minimum": 0
|
|
},
|
|
"genre": {
|
|
"description": "legacy, single",
|
|
"type": "string",
|
|
"maxLength": 100
|
|
},
|
|
"genres": {
|
|
"description": "v0.10.1: max 3, taxonomy slugs",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"is_public": {
|
|
"type": "boolean"
|
|
},
|
|
"musical_key": {
|
|
"type": "string",
|
|
"maxLength": 10
|
|
},
|
|
"tags": {
|
|
"description": "v0.10.1: max 10, 30 chars each",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"maxLength": 255,
|
|
"minLength": 1
|
|
},
|
|
"year": {
|
|
"type": "integer",
|
|
"maximum": 2100,
|
|
"minimum": 1900
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.APIResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {},
|
|
"error": {},
|
|
"success": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.AddCollaboratorRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"permission",
|
|
"user_id"
|
|
],
|
|
"properties": {
|
|
"permission": {
|
|
"type": "string",
|
|
"enum": [
|
|
"read",
|
|
"write",
|
|
"admin"
|
|
]
|
|
},
|
|
"user_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.AddQueueItemRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"track_id"
|
|
],
|
|
"properties": {
|
|
"track_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.AddToSessionRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"track_id"
|
|
],
|
|
"properties": {
|
|
"track_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.CreateCommentRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"content"
|
|
],
|
|
"properties": {
|
|
"content": {
|
|
"type": "string",
|
|
"maxLength": 5000,
|
|
"minLength": 1
|
|
},
|
|
"parent_id": {
|
|
"type": "string"
|
|
},
|
|
"timestamp": {
|
|
"description": "Position in seconds (0 = top-level, no specific time)",
|
|
"type": "number"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.CreateOrderRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"items"
|
|
],
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": {
|
|
"type": "object",
|
|
"required": [
|
|
"product_id"
|
|
],
|
|
"properties": {
|
|
"product_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"promo_code": {
|
|
"type": "string",
|
|
"maxLength": 50
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.CreatePlaylistRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"title"
|
|
],
|
|
"properties": {
|
|
"description": {
|
|
"type": "string",
|
|
"maxLength": 1000
|
|
},
|
|
"is_public": {
|
|
"type": "boolean"
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"maxLength": 200,
|
|
"minLength": 1
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.CreateProductRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"price",
|
|
"product_type",
|
|
"title"
|
|
],
|
|
"properties": {
|
|
"bpm": {
|
|
"description": "v0.401 M1",
|
|
"type": "integer",
|
|
"maximum": 300,
|
|
"minimum": 1
|
|
},
|
|
"category": {
|
|
"type": "string",
|
|
"enum": [
|
|
"sample",
|
|
"beat",
|
|
"preset",
|
|
"pack"
|
|
]
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"maxLength": 2000
|
|
},
|
|
"license_type": {
|
|
"type": "string",
|
|
"enum": [
|
|
"standard",
|
|
"exclusive",
|
|
"commercial"
|
|
]
|
|
},
|
|
"licenses": {
|
|
"description": "v0.401 M2: Product licenses (streaming, personal, commercial, exclusive)",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": [
|
|
"license_type",
|
|
"price_cents"
|
|
],
|
|
"properties": {
|
|
"license_type": {
|
|
"type": "string",
|
|
"enum": [
|
|
"streaming",
|
|
"personal",
|
|
"commercial",
|
|
"exclusive"
|
|
]
|
|
},
|
|
"price_cents": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"terms_text": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"musical_key": {
|
|
"type": "string",
|
|
"maxLength": 10
|
|
},
|
|
"price": {
|
|
"type": "number",
|
|
"minimum": 0
|
|
},
|
|
"product_type": {
|
|
"type": "string",
|
|
"enum": [
|
|
"track",
|
|
"pack",
|
|
"service"
|
|
]
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"maxLength": 200,
|
|
"minLength": 3
|
|
},
|
|
"track_id": {
|
|
"description": "UUID string",
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.DashboardResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"library_preview": {
|
|
"$ref": "#/definitions/internal_handlers.LibraryPreview"
|
|
},
|
|
"recent_activity": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/internal_handlers.RecentActivity"
|
|
}
|
|
},
|
|
"stats": {
|
|
"$ref": "#/definitions/internal_handlers.DashboardStats"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.DashboardStats": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.DeleteAccountRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"confirm_text",
|
|
"password"
|
|
],
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.DisableTwoFactorRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"password"
|
|
],
|
|
"properties": {
|
|
"password": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.FrontendLogRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"context": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"data": {},
|
|
"level": {
|
|
"type": "string"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"timestamp": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.ImportPlaylistRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"playlist": {
|
|
"type": "object",
|
|
"properties": {
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"is_public": {
|
|
"type": "boolean"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.LibraryPreview": {
|
|
"type": "object",
|
|
"properties": {
|
|
"has_more": {
|
|
"type": "boolean"
|
|
},
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/internal_handlers.TrackPreview"
|
|
}
|
|
},
|
|
"total_count": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.RecentActivity": {
|
|
"type": "object",
|
|
"properties": {
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"icon": {
|
|
"type": "string"
|
|
},
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"metadata": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"timestamp": {
|
|
"type": "string"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
},
|
|
"type": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.ReorderTracksRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"track_ids"
|
|
],
|
|
"properties": {
|
|
"track_ids": {
|
|
"description": "Changed to []uuid.UUID",
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.RequestPasswordResetRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"email"
|
|
],
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.ResetPasswordRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"new_password",
|
|
"token"
|
|
],
|
|
"properties": {
|
|
"new_password": {
|
|
"type": "string",
|
|
"minLength": 12
|
|
},
|
|
"token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.SetupTwoFactorResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"qr_code_url": {
|
|
"type": "string"
|
|
},
|
|
"recovery_codes": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"secret": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.StreamTokenResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"expires_in": {
|
|
"description": "seconds",
|
|
"type": "integer"
|
|
},
|
|
"token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.TrackPreview": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.UpdateCollaboratorPermissionRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"permission"
|
|
],
|
|
"properties": {
|
|
"permission": {
|
|
"type": "string",
|
|
"enum": [
|
|
"read",
|
|
"write",
|
|
"admin"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.UpdateCommentRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"content"
|
|
],
|
|
"properties": {
|
|
"content": {
|
|
"type": "string",
|
|
"maxLength": 5000,
|
|
"minLength": 1
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.UpdatePlaylistRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"description": {
|
|
"type": "string",
|
|
"maxLength": 1000
|
|
},
|
|
"is_public": {
|
|
"type": "boolean"
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"maxLength": 200,
|
|
"minLength": 1
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.UpdateProductRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"bpm": {
|
|
"type": "integer",
|
|
"maximum": 300,
|
|
"minimum": 1
|
|
},
|
|
"category": {
|
|
"type": "string",
|
|
"enum": [
|
|
"sample",
|
|
"beat",
|
|
"preset",
|
|
"pack"
|
|
]
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"maxLength": 2000
|
|
},
|
|
"licenses": {
|
|
"description": "v0.401 M2: Product licenses",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"required": [
|
|
"license_type",
|
|
"price_cents"
|
|
],
|
|
"properties": {
|
|
"license_type": {
|
|
"type": "string",
|
|
"enum": [
|
|
"streaming",
|
|
"personal",
|
|
"commercial",
|
|
"exclusive"
|
|
]
|
|
},
|
|
"price_cents": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"terms_text": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"musical_key": {
|
|
"type": "string",
|
|
"maxLength": 10
|
|
},
|
|
"price": {
|
|
"type": "number",
|
|
"minimum": 0
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"enum": [
|
|
"draft",
|
|
"active",
|
|
"archived"
|
|
]
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"maxLength": 200,
|
|
"minLength": 3
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.UpdateProfileRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"banner_url": {
|
|
"type": "string",
|
|
"maxLength": 2048
|
|
},
|
|
"bio": {
|
|
"type": "string",
|
|
"maxLength": 500
|
|
},
|
|
"birthdate": {
|
|
"type": "string"
|
|
},
|
|
"first_name": {
|
|
"type": "string",
|
|
"maxLength": 100
|
|
},
|
|
"gender": {
|
|
"type": "string",
|
|
"enum": [
|
|
"Male",
|
|
"Female",
|
|
"Other",
|
|
"Prefer not to say"
|
|
]
|
|
},
|
|
"is_public": {
|
|
"type": "boolean"
|
|
},
|
|
"last_name": {
|
|
"type": "string",
|
|
"maxLength": 100
|
|
},
|
|
"location": {
|
|
"type": "string",
|
|
"maxLength": 100
|
|
},
|
|
"social_links": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"username": {
|
|
"type": "string",
|
|
"maxLength": 30,
|
|
"minLength": 3
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.ValidateRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"data",
|
|
"type"
|
|
],
|
|
"properties": {
|
|
"data": {
|
|
"description": "The data to validate",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "integer"
|
|
}
|
|
},
|
|
"type": {
|
|
"description": "e.g., \"RegisterRequest\", \"LoginRequest\"",
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.ValidateResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"errors": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.ValidationError"
|
|
}
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"valid": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"internal_handlers.VerifyTwoFactorRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"code",
|
|
"secret"
|
|
],
|
|
"properties": {
|
|
"code": {
|
|
"description": "TOTP code to verify",
|
|
"type": "string"
|
|
},
|
|
"secret": {
|
|
"description": "Secret from setup step",
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.LicenseType": {
|
|
"type": "string",
|
|
"enum": [
|
|
"basic",
|
|
"premium",
|
|
"exclusive"
|
|
],
|
|
"x-enum-varnames": [
|
|
"LicenseBasic",
|
|
"LicensePremium",
|
|
"LicenseExclusive"
|
|
]
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.Order": {
|
|
"type": "object",
|
|
"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": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.OrderItem"
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.OrderItem": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"order_id": {
|
|
"type": "string"
|
|
},
|
|
"price": {
|
|
"type": "number"
|
|
},
|
|
"product_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.Product": {
|
|
"type": "object",
|
|
"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": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.ProductImage"
|
|
}
|
|
},
|
|
"license_type": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.LicenseType"
|
|
},
|
|
"licenses": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.ProductLicense"
|
|
}
|
|
},
|
|
"musical_key": {
|
|
"type": "string"
|
|
},
|
|
"previews": {
|
|
"description": "Relations",
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_core_marketplace.ProductPreview"
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.ProductImage": {
|
|
"type": "object",
|
|
"properties": {
|
|
"created_at": {
|
|
"type": "string"
|
|
},
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"product_id": {
|
|
"type": "string"
|
|
},
|
|
"sort_order": {
|
|
"type": "integer"
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.ProductLicense": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.ProductPreview": {
|
|
"type": "object",
|
|
"properties": {
|
|
"created_at": {
|
|
"type": "string"
|
|
},
|
|
"duration_sec": {
|
|
"type": "integer"
|
|
},
|
|
"file_path": {
|
|
"type": "string"
|
|
},
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"product_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_core_marketplace.ProductStatus": {
|
|
"type": "string",
|
|
"enum": [
|
|
"draft",
|
|
"active",
|
|
"archived"
|
|
],
|
|
"x-enum-varnames": [
|
|
"ProductStatusDraft",
|
|
"ProductStatusActive",
|
|
"ProductStatusArchived"
|
|
]
|
|
},
|
|
"veza-backend-api_internal_dto.LoginRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"email",
|
|
"password"
|
|
],
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
},
|
|
"password": {
|
|
"type": "string"
|
|
},
|
|
"remember_me": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.LoginResponse": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.RefreshRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"refresh_token"
|
|
],
|
|
"properties": {
|
|
"refresh_token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.RegisterRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"email",
|
|
"password",
|
|
"password_confirmation"
|
|
],
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
},
|
|
"password": {
|
|
"type": "string",
|
|
"minLength": 12
|
|
},
|
|
"password_confirmation": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string",
|
|
"maxLength": 50,
|
|
"minLength": 3
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.RegisterResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"user": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_dto.UserResponse"
|
|
},
|
|
"verification_required": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.ResendVerificationRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"email"
|
|
],
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.TokenResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"access_token": {
|
|
"type": "string"
|
|
},
|
|
"expires_in": {
|
|
"type": "integer"
|
|
},
|
|
"refresh_token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.UserResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
},
|
|
"id": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_dto.ValidationError": {
|
|
"type": "object",
|
|
"properties": {
|
|
"field": {
|
|
"type": "string"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"value": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_handlers.APIResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {},
|
|
"error": {},
|
|
"success": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_models.Playlist": {
|
|
"type": "object",
|
|
"properties": {
|
|
"collaborators": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.PlaylistCollaborator"
|
|
}
|
|
},
|
|
"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": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/veza-backend-api_internal_models.PlaylistTrack"
|
|
}
|
|
},
|
|
"updated_at": {
|
|
"type": "string"
|
|
},
|
|
"user_id": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_models.PlaylistCollaborator": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_models.PlaylistPermission": {
|
|
"type": "string",
|
|
"enum": [
|
|
"read",
|
|
"write",
|
|
"admin"
|
|
],
|
|
"x-enum-varnames": [
|
|
"PlaylistPermissionRead",
|
|
"PlaylistPermissionWrite",
|
|
"PlaylistPermissionAdmin"
|
|
]
|
|
},
|
|
"veza-backend-api_internal_models.PlaylistTrack": {
|
|
"type": "object",
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_models.Track": {
|
|
"type": "object",
|
|
"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": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
},
|
|
"updated_at": {
|
|
"type": "string"
|
|
},
|
|
"waveform_path": {
|
|
"type": "string"
|
|
},
|
|
"waveform_url": {
|
|
"type": "string"
|
|
},
|
|
"year": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_models.TrackStatus": {
|
|
"type": "string",
|
|
"enum": [
|
|
"uploading",
|
|
"processing",
|
|
"completed",
|
|
"failed"
|
|
],
|
|
"x-enum-varnames": [
|
|
"TrackStatusUploading",
|
|
"TrackStatusProcessing",
|
|
"TrackStatusCompleted",
|
|
"TrackStatusFailed"
|
|
]
|
|
},
|
|
"veza-backend-api_internal_models.User": {
|
|
"type": "object",
|
|
"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'`\nvia POST /api/v1/users/me/upgrade-creator. NULL for users who never\ntook 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"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_response.APIResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"data": {},
|
|
"error": {},
|
|
"success": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"veza-backend-api_internal_services.UpdateQueueRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"current_position": {
|
|
"type": "integer"
|
|
},
|
|
"current_track_id": {
|
|
"type": "string"
|
|
},
|
|
"is_playing": {
|
|
"type": "boolean"
|
|
},
|
|
"item_order": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"repeat_mode": {
|
|
"type": "string"
|
|
},
|
|
"shuffle": {
|
|
"type": "boolean"
|
|
},
|
|
"volume": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"securityDefinitions": {
|
|
"ApiKeyAuth": {
|
|
"description": "Developer API key (obtain from Developer Portal). Format: vza_xxxxx",
|
|
"type": "apiKey",
|
|
"name": "X-API-Key",
|
|
"in": "header"
|
|
},
|
|
"BearerAuth": {
|
|
"type": "apiKey",
|
|
"name": "Authorization",
|
|
"in": "header"
|
|
}
|
|
}
|
|
} |