{ "openapi": "3.1.0", "info": { "title": "Scriberr API", "version": "v1" }, "paths": { "/health": { "get": { "summary": "Health check", "responses": { "200": { "description": "Service is alive" } } } }, "/api/v1/health": { "get": { "summary": "API health check", "responses": { "200": { "description": "API is alive" } } } }, "/api/v1/ready": { "get": { "summary": "Readiness check", "responses": { "200": { "description": "Service is ready" }, "503": { "description": "Service is not ready" } } } }, "/api/v1/auth/registration-status": { "get": { "summary": "Get registration status", "responses": { "200": { "description": "Registration status" } } } }, "/api/v1/auth/register": { "post": { "summary": "Register the local user", "responses": { "200": { "description": "Token response" }, "409": { "description": "Registration already completed" }, "422": { "description": "Validation error" } } } }, "/api/v1/auth/login": { "post": { "summary": "Log in", "responses": { "200": { "description": "Token response" }, "401": { "description": "Invalid credentials" } } } }, "/api/v1/auth/refresh": { "post": { "summary": "Rotate refresh token", "responses": { "200": { "description": "Token response" }, "401": { "description": "Invalid refresh token" } } } }, "/api/v1/auth/logout": { "post": { "summary": "Revoke refresh token", "responses": { "200": { "description": "Logout accepted" } } } }, "/api/v1/auth/me": { "get": { "summary": "Get current user", "responses": { "200": { "description": "Current user" }, "401": { "description": "Authentication required" } } } }, "/api/v1/auth/change-password": { "post": { "summary": "Change password", "responses": { "200": { "description": "Password changed" }, "401": { "description": "Authentication failed" }, "422": { "description": "Validation error" } } } }, "/api/v1/auth/change-username": { "post": { "summary": "Change username", "responses": { "200": { "description": "Username changed" }, "401": { "description": "Authentication failed" } } } }, "/api/v1/api-keys": { "get": { "summary": "List API keys", "responses": { "200": { "description": "API key list" }, "401": { "description": "JWT required" } } }, "post": { "summary": "Create API key", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key. Exact retries return the original successful response; mismatched reuse returns 409.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "201": { "description": "API key created" }, "401": { "description": "JWT required" } } } }, "/api/v1/api-keys/{id}": { "delete": { "summary": "Delete API key", "responses": { "204": { "description": "API key deleted" }, "401": { "description": "JWT required" }, "404": { "description": "API key not found" } } } }, "/api/v1/files": { "get": { "summary": "List files", "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "description": "Opaque pagination cursor returned as next_cursor." }, { "name": "q", "in": "query", "description": "Case-insensitive title search." }, { "name": "kind", "in": "query", "schema": { "type": "string", "enum": ["audio", "video", "youtube"] } }, { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["uploaded", "processing", "ready", "failed"] } }, { "name": "updated_after", "in": "query", "schema": { "type": "string", "format": "date-time" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["created_at", "-created_at", "updated_at", "-updated_at", "title", "-title"] } } ], "responses": { "200": { "description": "File list" }, "401": { "description": "Authentication required" }, "422": { "description": "Invalid query parameter" } } }, "post": { "summary": "Upload file", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for upload creation.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "201": { "description": "File uploaded" }, "400": { "description": "Invalid upload" }, "401": { "description": "Authentication required" }, "413": { "description": "Upload too large" }, "415": { "description": "Unsupported media type" } } } }, "/api/v1/files:import-youtube": { "post": { "summary": "Import YouTube media", "description": "Creates a processing YouTube file resource, downloads media asynchronously through the configured importer, then transitions the file to ready or failed. Events are published as file.processing, file.ready, or file.failed.", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for YouTube import creation.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "202": { "description": "YouTube import accepted with status processing" }, "401": { "description": "Authentication required" }, "409": { "description": "Idempotency key conflict" }, "422": { "description": "Validation error, including unsupported URL host or scheme" } } } }, "/api/v1/files/{id}": { "get": { "summary": "Get file", "responses": { "200": { "description": "File" }, "404": { "description": "File not found" } } }, "patch": { "summary": "Update file metadata", "responses": { "200": { "description": "File updated" }, "422": { "description": "Validation error" } } }, "delete": { "summary": "Delete file", "responses": { "204": { "description": "File deleted" } } } }, "/api/v1/files/{id}/audio": { "get": { "summary": "Stream file audio", "responses": { "200": { "description": "Audio stream" }, "206": { "description": "Partial audio stream" }, "416": { "description": "Invalid range" } } } }, "/api/v1/transcriptions": { "get": { "summary": "List transcriptions", "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "description": "Opaque pagination cursor returned as next_cursor." }, { "name": "q", "in": "query", "description": "Case-insensitive title search." }, { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["queued", "processing", "completed", "failed", "canceled"] } }, { "name": "updated_after", "in": "query", "schema": { "type": "string", "format": "date-time" } }, { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["created_at", "-created_at", "updated_at", "-updated_at", "title", "-title"] } } ], "responses": { "200": { "description": "Transcription list" }, "401": { "description": "Authentication required" }, "422": { "description": "Invalid query parameter" } } }, "post": { "summary": "Create transcription", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for transcription creation.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "202": { "description": "Transcription queued" }, "404": { "description": "Source file not found" }, "422": { "description": "Validation error" } } } }, "/api/v1/transcriptions:submit": { "post": { "summary": "Upload and create transcription", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for combined upload and transcription creation.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "202": { "description": "File uploaded and transcription queued" }, "400": { "description": "Invalid multipart request" }, "415": { "description": "Unsupported media type" } } } }, "/api/v1/transcriptions/{id}": { "get": { "summary": "Get transcription", "responses": { "200": { "description": "Transcription" }, "404": { "description": "Transcription not found" } } }, "patch": { "summary": "Update transcription metadata", "responses": { "200": { "description": "Transcription updated" } } }, "delete": { "summary": "Delete transcription", "responses": { "204": { "description": "Transcription deleted" } } } }, "/api/v1/transcriptions/{id}:cancel": { "post": { "summary": "Cancel transcription", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for cancel command.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "200": { "description": "Transcription canceled" }, "409": { "description": "State conflict" } } } }, "/api/v1/transcriptions/{id}:retry": { "post": { "summary": "Retry transcription", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for retry command.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "202": { "description": "Retry queued" } } } }, "/api/v1/transcriptions/{id}/transcript": { "get": { "summary": "Get transcript", "responses": { "200": { "description": "Transcript" } } } }, "/api/v1/transcriptions/{id}/audio": { "get": { "summary": "Stream transcription audio", "responses": { "200": { "description": "Audio stream" }, "206": { "description": "Partial audio stream" } } } }, "/api/v1/transcriptions/{id}/events": { "get": { "summary": "Stream transcription events", "description": "Authenticated Server-Sent Events stream filtered to the requested transcription. Replay with Last-Event-ID is not supported yet.", "responses": { "200": { "description": "SSE stream using text/event-stream" }, "401": { "description": "Authentication required" }, "404": { "description": "Transcription not found" } } } }, "/api/v1/transcriptions/{id}/logs": { "get": { "summary": "Get transcription logs", "responses": { "501": { "description": "Deferred placeholder" } } } }, "/api/v1/transcriptions/{id}/executions": { "get": { "summary": "Get transcription executions", "responses": { "501": { "description": "Deferred placeholder" } } } }, "/api/v1/profiles": { "get": { "summary": "List profiles", "responses": { "200": { "description": "Profile list" } } }, "post": { "summary": "Create profile", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for profile creation.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "201": { "description": "Profile created" }, "422": { "description": "Validation error" } } } }, "/api/v1/profiles/{id}": { "get": { "summary": "Get profile", "responses": { "200": { "description": "Profile" }, "404": { "description": "Profile not found" } } }, "patch": { "summary": "Update profile", "responses": { "200": { "description": "Profile updated" } } }, "delete": { "summary": "Delete profile", "responses": { "204": { "description": "Profile deleted" } } } }, "/api/v1/profiles/{id}:set-default": { "post": { "summary": "Set default profile", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Optional retry key for set-default command.", "schema": { "type": "string", "maxLength": 128 } } ], "responses": { "200": { "description": "Profile set as default" } } } }, "/api/v1/settings": { "get": { "summary": "Get settings", "responses": { "200": { "description": "Settings" } } }, "patch": { "summary": "Update settings", "responses": { "200": { "description": "Settings updated" }, "422": { "description": "Validation error" } } } }, "/api/v1/events": { "get": { "summary": "Stream global events", "description": "Authenticated Server-Sent Events stream for API-visible file, transcription, profile, and settings changes. Replay with Last-Event-ID is not supported yet.", "responses": { "200": { "description": "SSE stream using text/event-stream" }, "401": { "description": "Authentication required" } } } }, "/api/v1/models/transcription": { "get": { "summary": "List transcription models", "responses": { "200": { "description": "Model capabilities" } } } }, "/api/v1/admin/queue": { "get": { "summary": "Queue stats", "responses": { "200": { "description": "Queue stats" } } } } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer" }, "apiKeyAuth": { "type": "apiKey", "in": "header", "name": "X-API-Key" } } } }