{"openapi": "3.0.3", "info": {"title": "AXIS Foundry API", "version": "1.1.0", "description": "HTTP API for AXIS Foundry avatar processing pipeline. All responses include a unique request_id for tracing."}, "components": {"schemas": {"SuccessResponse": {"type": "object", "required": ["status", "data", "request_id"], "properties": {"status": {"type": "string", "enum": ["ok"]}, "data": {"type": "object"}, "request_id": {"type": "string", "description": "Unique 12-char hex trace ID"}}}, "ErrorResponse": {"type": "object", "required": ["status", "error", "error_code", "request_id"], "properties": {"status": {"type": "string", "enum": ["error"]}, "error": {"type": "string", "description": "Human-readable error message"}, "error_code": {"type": "string", "enum": ["BAD_REQUEST", "UNAUTHORIZED", "NOT_FOUND", "RATE_LIMITED", "INTERNAL_ERROR"]}, "request_id": {"type": "string"}, "detail": {"type": "string", "description": "Optional structured detail"}}}, "BoundsInt": {"type": "integer", "description": "Server-enforced bounded integer parameter"}, "RateLimitResponse": {"type": "object", "required": ["status", "error", "error_code", "is_retryable", "retry_after"], "properties": {"status": {"type": "string", "enum": ["error"]}, "error": {"type": "string"}, "error_code": {"type": "string", "enum": ["RATE_LIMITED"]}, "request_id": {"type": "string"}, "is_retryable": {"type": "boolean", "enum": [true]}, "retry_after": {"type": "number", "description": "Seconds to wait before retrying"}}}}, "securitySchemes": {"BearerAuth": {"type": "http", "scheme": "bearer", "description": "Portal session token obtained from POST /portal/api/login"}, "ApiKeyAuth": {"type": "apiKey", "in": "header", "name": "X-API-Key", "description": "API key with scoped permissions"}}}, "security": [{"BearerAuth": []}, {"ApiKeyAuth": []}], "paths": {"/health": {"get": {"summary": "Runtime health check with diagnostics", "tags": ["meta"], "security": [], "responses": {"200": {"description": "Health diagnostics (not envelope-wrapped)", "content": {"application/json": {"schema": {"type": "object", "required": ["status", "version", "checks"], "properties": {"status": {"type": "string", "enum": ["ok", "degraded"]}, "version": {"type": "string"}, "checks": {"type": "object", "properties": {"job_store": {"type": "string"}, "gallery_store": {"type": "string"}, "generation_providers": {"type": "array", "items": {"type": "string"}}, "gpu_endpoint": {"type": "string", "enum": ["configured", "not_configured"]}}}}}}}}}}}, "/openapi.json": {"get": {"summary": "This OpenAPI specification", "tags": ["meta"], "security": [], "responses": {"200": {"description": "OpenAPI 3.0 spec"}}}}, "/api/platforms": {"get": {"summary": "List supported export platforms", "tags": ["discovery"], "security": [], "responses": {"200": {"description": "Platform list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/backends": {"get": {"summary": "List available mesh generation backends", "tags": ["discovery"], "security": [], "responses": {"200": {"description": "Backend list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/capabilities": {"get": {"summary": "List runtime-discovered capabilities", "tags": ["discovery"], "security": [], "parameters": [{"name": "kind", "in": "query", "required": false, "schema": {"type": "string"}}, {"name": "tag", "in": "query", "required": false, "schema": {"type": "string"}}, {"name": "available", "in": "query", "required": false, "schema": {"type": "boolean"}}], "responses": {"200": {"description": "Capability list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid query parameter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/search": {"get": {"summary": "Search capabilities and route actionable intent", "tags": ["discovery"], "security": [], "parameters": [{"name": "q", "in": "query", "required": false, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}}], "responses": {"200": {"description": "Search result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid query parameter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/diagnostics": {"get": {"summary": "Runtime diagnostics (GPU, memory, versions)", "tags": ["discovery"], "security": [], "responses": {"200": {"description": "Diagnostics object", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/release-check": {"get": {"summary": "Release contract with health probing and gate evaluation", "tags": ["meta"], "security": [], "parameters": [{"name": "probe", "in": "query", "schema": {"type": "boolean", "default": false}, "description": "Probe all unit health endpoints live"}, {"name": "timeout", "in": "query", "schema": {"type": "number", "default": 10, "maximum": 30}, "description": "Health probe timeout in seconds"}], "responses": {"200": {"description": "Release contract with gates and health results", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/pipeline/stages": {"get": {"summary": "List registered pipeline stages", "tags": ["discovery"], "responses": {"200": {"description": "Stage list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/agent/handlers": {"get": {"summary": "List AI agent action handlers", "tags": ["discovery"], "responses": {"200": {"description": "Handler list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/ai/providers": {"get": {"summary": "List AI provider capabilities", "tags": ["discovery"], "responses": {"200": {"description": "Provider list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/repair/types": {"get": {"summary": "List available repair strategies", "tags": ["discovery"], "responses": {"200": {"description": "Repair types", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/audit/formats": {"get": {"summary": "List audit export formats", "tags": ["discovery"], "responses": {"200": {"description": "Format list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/fraud/stats": {"get": {"summary": "Fraud detection statistics", "tags": ["discovery"], "responses": {"200": {"description": "Fraud stats", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/info": {"get": {"summary": "Get avatar info from file path", "tags": ["query"], "parameters": [{"name": "path", "in": "query", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Avatar info", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Missing or invalid path", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"description": "File not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/preview": {"get": {"summary": "Generate WebGL preview HTML", "tags": ["query"], "parameters": [{"name": "preset", "in": "query", "required": false, "schema": {"type": "string"}}, {"name": "animate", "in": "query", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"description": "HTML preview page"}}}}, "/api/export/{id}": {"get": {"summary": "Download cached GLB or get export metadata", "tags": ["query"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "format", "in": "query", "schema": {"type": "string", "enum": ["glb", "gltf", "obj", "stl"], "default": "glb"}}, {"name": "info", "in": "query", "schema": {"type": "string", "enum": ["true", "1"]}, "description": "Return JSON metadata instead of binary"}], "responses": {"200": {"description": "Binary file or JSON metadata (when info=true)", "content": {"model/gltf-binary": {}, "application/json": {}}}, "404": {"description": "Export not found or expired", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/formats": {"get": {"summary": "Supported import/export formats and target platforms", "tags": ["query"], "description": "Returns import formats (8 types), export formats (4 types), and platform-specific export targets with coordinate system info.", "responses": {"200": {"description": "Format and platform discovery", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/status": {"get": {"summary": "Get service status or poll async job status via query parameter", "tags": ["query"], "parameters": [{"name": "job_id", "in": "query", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"description": "Service status or job status with progress", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "404": {"description": "Job not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/job/{job_id}": {"get": {"summary": "Poll async job status", "tags": ["query"], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Job status with progress", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "404": {"description": "Job not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/review/pending": {"get": {"summary": "List pending human-in-loop review items", "tags": ["query"], "responses": {"200": {"description": "Pending reviews", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/review/{review_id}": {"get": {"summary": "Fetch specific review item details", "tags": ["query"], "parameters": [{"name": "review_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Review item", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "404": {"description": "Review item not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/process": {"post": {"summary": "Process a mesh file through the pipeline", "tags": ["pipeline"], "parameters": [{"name": "platform", "in": "query", "required": false, "schema": {"type": "string", "enum": ["unity", "unreal", "godot", "roblox", "axis_engine"]}}, {"name": "profile", "in": "query", "required": false, "schema": {"type": "string", "enum": ["default", "strict", "lenient"]}}, {"name": "polygon_tier", "in": "query", "required": false, "schema": {"type": "string", "enum": ["mobile_light", "mobile_standard", "web_vr", "desktop_standard", "desktop_high", "film_vfx", "ultra_hd"]}}], "responses": {"200": {"description": "Pipeline result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "500": {"description": "Pipeline error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/process/stream": {"post": {"summary": "Process with SSE progress events", "tags": ["pipeline"], "responses": {"200": {"description": "Server-Sent Events stream"}}}}, "/api/validate": {"post": {"summary": "Validate a mesh file", "tags": ["pipeline"], "responses": {"200": {"description": "Validation result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/rig": {"post": {"summary": "Auto-rig an uploaded mesh (standalone)", "tags": ["pipeline"], "description": "Upload a GLB or OBJ file, auto-detect archetype, fit skeleton, and return rigged GLB.", "parameters": [{"name": "platform", "in": "query", "required": false, "schema": {"type": "string", "enum": ["unity", "unreal", "godot", "roblox", "axis_engine"]}}], "responses": {"200": {"description": "Rig result with download URL", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid or missing file", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "500": {"description": "Rigging failed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/pipeline/run-stage": {"post": {"summary": "Run a specific pipeline stage by name", "tags": ["pipeline"], "responses": {"200": {"description": "Stage result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Unknown stage or invalid params", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/generate": {"post": {"summary": "Generate a parametric avatar", "tags": ["generation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"preset": {"type": "string"}, "prompt": {"type": "string"}, "platform": {"type": "string", "enum": ["unity", "unreal", "godot", "roblox", "axis_engine"]}, "morph_targets": {"type": "boolean", "default": false}, "lods": {"type": "boolean", "default": false}, "no_face": {"type": "boolean", "default": false}, "polygon_tier": {"type": "string", "enum": ["mobile_light", "mobile_standard", "web_vr", "desktop_standard", "desktop_high", "film_vfx", "ultra_hd"]}}}}}}, "responses": {"200": {"description": "Generation result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid parameters", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/generate-from-image": {"post": {"summary": "Generate avatar from a single image (image-to-3D)", "tags": ["generation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["image_b64"], "properties": {"image_b64": {"type": "string", "description": "Base64-encoded image"}, "platform": {"type": "string", "default": "unreal"}, "voxel_resolution": {"type": "integer", "minimum": 8, "maximum": 128, "default": 32}, "texture_resolution": {"type": "integer", "minimum": 64, "maximum": 2048, "default": 256}}}}}}, "responses": {"200": {"description": "Async job with poll URL", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid image or parameters", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/generate-from-views": {"post": {"summary": "Generate avatar from multiple view images (multi-view fusion)", "tags": ["generation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["views"], "properties": {"views": {"type": "array", "items": {"type": "object", "properties": {"image_b64": {"type": "string"}, "view_label": {"type": "string", "enum": ["front", "back", "left", "right", "three_quarter", "detail", "custom"]}}}}, "platform": {"type": "string", "default": "unreal"}, "voxel_resolution": {"type": "integer", "minimum": 8, "maximum": 128, "default": 32}, "texture_resolution": {"type": "integer", "minimum": 64, "maximum": 2048, "default": 256}}}}}}, "responses": {"200": {"description": "Async job with poll URL", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid views or parameters", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/batch-generate": {"post": {"summary": "Batch generate multiple avatars", "tags": ["generation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["items"], "properties": {"items": {"type": "array", "items": {"type": "object", "properties": {"preset": {"type": "string"}, "prompt": {"type": "string"}, "platform": {"type": "string", "enum": ["unity", "unreal", "godot", "roblox", "axis_engine"]}, "morph_targets": {"type": "boolean", "default": false}, "lods": {"type": "boolean", "default": false}, "no_face": {"type": "boolean", "default": false}, "polygon_tier": {"type": "string", "enum": ["mobile_light", "mobile_standard", "web_vr", "desktop_standard", "desktop_high", "film_vfx", "ultra_hd"]}}}}}}}}}, "responses": {"200": {"description": "Batch result with per-item status", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid batch request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/batch-generate/stream": {"post": {"summary": "Batch generate with SSE progress events", "tags": ["generation"], "responses": {"200": {"description": "Server-Sent Events stream"}}}}, "/api/foundry/providers": {"get": {"summary": "List registered generation providers with capabilities", "tags": ["foundry"], "responses": {"200": {"description": "Provider list with per-provider capabilities", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/foundry/profiles": {"get": {"summary": "List available output profiles", "tags": ["foundry"], "responses": {"200": {"description": "Output profile enum values: game_ready, dcc_editable, print_ready", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/foundry/modes": {"get": {"summary": "List available generation modes", "tags": ["foundry"], "responses": {"200": {"description": "Generation mode enum values: text_to_3d, image_to_3d, avatar_parametric, mesh_upload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/model-readiness": {"get": {"summary": "Provider health, capability readiness, and transition strategy", "tags": ["foundry"], "description": "Returns per-provider availability, capabilities, latency, capability matrix, provider transition strategy, and readiness evaluation against criteria.", "responses": {"200": {"description": "Provider health list with capability_matrix, transition plan, provider_readiness evaluations, all_healthy flag and counts", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/foundry/routing-config": {"get": {"summary": "Get current generation routing configuration", "tags": ["foundry"], "description": "Returns the router's preferred provider order, fallback config, retry settings, and selection flags.", "responses": {"200": {"description": "Routing configuration: preferred_order, fallback, retry, flags", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/foundry/generate": {"post": {"summary": "Provider-agnostic async generation via the routing engine", "tags": ["foundry"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["mode"], "properties": {"mode": {"type": "string", "enum": ["text_to_3d", "image_to_3d", "avatar_parametric", "mesh_upload"]}, "text_prompt": {"type": "string", "description": "Required for text_to_3d mode"}, "image_b64": {"type": "string", "description": "Base64-encoded image for image_to_3d mode"}, "asset_class": {"type": "string", "enum": ["avatar", "object", "scene"], "default": "avatar"}, "output_profile": {"type": "string", "enum": ["game_ready", "dcc_editable", "print_ready"], "default": "game_ready"}, "asset_category": {"type": "string", "enum": ["character", "prop", "hard_surface", "stylized", "print"]}, "preferred_provider": {"type": "string", "description": "Optional provider name hint (e.g. trellis2, parametric)"}, "preset_id": {"type": "string", "description": "Required for avatar_parametric mode unless body_proportions is provided"}, "body_proportions": {"type": "object", "description": "Optional parametric body proportions for avatar_parametric mode"}, "face_proportions": {"type": "object", "description": "Optional parametric face proportions for avatar_parametric mode"}, "target_polycount": {"type": "integer", "minimum": 100, "maximum": 500000}, "texture_size": {"type": "integer", "enum": [256, 512, 1024, 2048, 4096]}, "seed": {"type": "integer", "description": "Optional RNG seed for reproducibility"}}}}}}, "responses": {"200": {"description": "Async job: {job_id, status, poll_url, request_id}", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid mode, profile, or category", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "402": {"description": "Insufficient tokens", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/gallery": {"get": {"summary": "List gallery assets for a user", "tags": ["gallery"], "parameters": [{"name": "user_id", "in": "query", "schema": {"type": "string", "default": "anonymous"}}, {"name": "asset_class", "in": "query", "schema": {"type": "string", "enum": ["avatar", "object", "scene"]}, "description": "Filter by asset class"}, {"name": "category", "in": "query", "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}, {"name": "offset", "in": "query", "schema": {"type": "integer", "default": 0}}], "responses": {"200": {"description": "Paginated asset list with total count", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/gallery/{asset_id}": {"get": {"summary": "Get a single gallery asset by ID", "tags": ["gallery"], "parameters": [{"name": "asset_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Gallery asset details", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "404": {"description": "Asset not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/gallery/delete": {"post": {"summary": "Delete a gallery asset", "tags": ["gallery"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["asset_id"], "properties": {"asset_id": {"type": "string"}, "user_id": {"type": "string", "default": "anonymous"}}}}}}, "responses": {"200": {"description": "Deletion confirmed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "404": {"description": "Asset not found or not owned", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/auth/verify": {"get": {"summary": "Verify authentication credentials", "tags": ["auth"], "description": "Echo back the authenticated user identity, auth method, and plan. Use to validate credentials before making billable requests.", "responses": {"200": {"description": "Auth verification with user_id, auth_method, plan", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/gallery/my-assets": {"get": {"summary": "List gallery assets for the authenticated user", "tags": ["gallery"], "description": "Auto-resolves user identity from Bearer or X-API-Key auth. Returns paginated assets owned by the caller.", "parameters": [{"name": "asset_class", "in": "query", "schema": {"type": "string", "enum": ["avatar", "object", "scene"]}, "description": "Filter by asset class"}, {"name": "category", "in": "query", "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}, {"name": "offset", "in": "query", "schema": {"type": "integer", "default": 0}}], "responses": {"200": {"description": "Paginated asset list with user_id and total count", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/contracts/aggregate": {"get": {"summary": "Aggregate contracts by a field", "tags": ["contracts"], "description": "Group avatar contracts by a dot-notation field path and compute per-group aggregate metrics.", "parameters": [{"name": "group_by", "in": "query", "required": true, "schema": {"type": "string"}, "description": "Dot-notation field path to group by (e.g. 'stage', 'mesh.quality_grade')"}, {"name": "metrics", "in": "query", "schema": {"type": "string"}, "description": "Comma-separated numeric field paths to aggregate (e.g. 'mesh.vertex_count,mesh.quality_score')"}, {"name": "stage", "in": "query", "schema": {"type": "string"}, "description": "Optional lifecycle stage filter"}, {"name": "user_id", "in": "query", "schema": {"type": "string", "default": "anonymous"}, "description": "Gallery owner user_id to aggregate"}, {"name": "include_empty", "in": "query", "schema": {"type": "boolean", "default": true}, "description": "Include empty/null group keys in bucket output"}, {"name": "sort", "in": "query", "schema": {"type": "string", "enum": ["key_asc", "key_desc", "count_desc", "count_asc", "count"], "default": "key_asc"}, "description": "Bucket ordering strategy (count aliases to count_desc)"}, {"name": "min_count", "in": "query", "schema": {"type": "integer", "default": 0, "minimum": 0}, "description": "Only include buckets with count >= min_count"}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}, "description": "Maximum number of buckets to return"}, {"name": "offset", "in": "query", "schema": {"type": "integer", "default": 0}, "description": "Bucket pagination offset"}], "responses": {"200": {"description": "GroupAggregation result with buckets and metrics", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Missing or invalid group_by parameter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/billing/balance": {"get": {"summary": "Get current billing balance and plan info", "tags": ["billing"], "description": "Returns plan name, token balance, and per-mode token costs. Requires Bearer or X-API-Key auth.", "responses": {"200": {"description": "Billing balance", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/billing/usage": {"get": {"summary": "Get recent billing transactions", "tags": ["billing"], "description": "Returns recent token deductions and refunds. Requires Bearer or X-API-Key auth.", "parameters": [{"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}], "responses": {"200": {"description": "List of billing transactions", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/quality-policy": {"get": {"summary": "Get effective quality refusal policy for caller", "tags": ["quality"], "description": "Returns the quality gate thresholds that apply to the caller's billing tier. Optional profile query param narrows to a specific output profile.", "parameters": [{"name": "profile", "in": "query", "schema": {"type": "string"}, "description": "Output profile (e.g. game_ready, dcc_editable, print_ready)"}], "responses": {"200": {"description": "Effective quality policy with min_quality_score, min_quality_grade, tier", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/agent/run": {"post": {"summary": "Run an AI agent with a natural language goal", "tags": ["ai"], "responses": {"200": {"description": "Agent execution result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Missing goal", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/prompt-pipeline": {"post": {"summary": "Run the prompt-to-avatar pipeline", "tags": ["ai"], "responses": {"200": {"description": "Prompt pipeline result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid prompt", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/audit/contract": {"post": {"summary": "Audit and validate an avatar contract", "tags": ["audit"], "responses": {"200": {"description": "Audit result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid contract data", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/audit/glb": {"post": {"summary": "Audit a GLB binary for compliance", "tags": ["audit"], "responses": {"200": {"description": "GLB audit result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/repair/suggest": {"post": {"summary": "Suggest repairs for a mesh or contract", "tags": ["audit"], "responses": {"200": {"description": "Repair suggestions", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/api/review/decide": {"post": {"summary": "Submit a human-in-loop review decision", "tags": ["audit"], "responses": {"200": {"description": "Decision recorded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid decision", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/api/fraud/check": {"post": {"summary": "Check an avatar for fraud indicators", "tags": ["audit"], "responses": {"200": {"description": "Fraud check result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/portal/api/signup": {"post": {"summary": "Create a portal account", "tags": ["portal"], "security": [], "responses": {"200": {"description": "Signup succeeded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid signup payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "409": {"description": "Account already exists", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/login": {"post": {"summary": "Authenticate a portal account", "tags": ["portal"], "security": [], "responses": {"200": {"description": "Login succeeded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Invalid credentials", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "403": {"description": "Account suspended", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "429": {"description": "Too many login attempts", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/avatars": {"get": {"summary": "List authenticated user's portal avatars", "tags": ["portal"], "responses": {"200": {"description": "Avatar list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"summary": "Create a portal avatar record", "tags": ["portal"], "responses": {"200": {"description": "Avatar created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid avatar payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"summary": "Delete a portal avatar record", "tags": ["portal"], "responses": {"200": {"description": "Avatar deleted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/account": {"get": {"summary": "Get authenticated account details", "tags": ["portal"], "responses": {"200": {"description": "Account details", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"summary": "Delete authenticated account", "tags": ["portal"], "responses": {"200": {"description": "Account deleted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/keys": {"get": {"summary": "List API keys for authenticated account", "tags": ["portal"], "responses": {"200": {"description": "API key list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"summary": "Create API key for authenticated account", "tags": ["portal"], "responses": {"200": {"description": "API key created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"summary": "Revoke API key for authenticated account", "tags": ["portal"], "responses": {"200": {"description": "API key revoked", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/deduct": {"post": {"summary": "Deduct portal tokens for an operation", "tags": ["portal"], "responses": {"200": {"description": "Token deduction result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid deduction payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/profile": {"post": {"summary": "Update profile for authenticated account", "tags": ["portal"], "responses": {"200": {"description": "Profile updated", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid profile payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/password": {"post": {"summary": "Change password for authenticated account", "tags": ["portal"], "responses": {"200": {"description": "Password updated", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid password payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/billing/checkout": {"post": {"summary": "Create TrustFabric checkout payment intent for token packs", "tags": ["portal", "billing"], "description": "Creates a payment intent via TrustFabric/PAI'D. Body requires token_pack.", "responses": {"200": {"description": "Checkout intent created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Unknown or invalid token pack", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "502": {"description": "Payment processor error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "503": {"description": "Payments not configured", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/billing/options": {"get": {"summary": "Get billing plans and token-pack options for the frontend", "tags": ["portal", "billing"], "responses": {"200": {"description": "Billing options", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}}}}, "/portal/api/logout": {"post": {"summary": "Invalidate the current portal session token", "tags": ["portal"], "responses": {"200": {"description": "Session invalidated", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/eligibility": {"get": {"summary": "Check BYOGPU subscription eligibility for the authenticated account", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Eligibility report", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/subscribe": {"post": {"summary": "Subscribe the authenticated account to the BYOGPU plan", "tags": ["portal", "byogpu", "billing"], "responses": {"200": {"description": "Subscription started or checkout intent created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid subscription payload", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "502": {"description": "Payment processor error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "503": {"description": "Payments not configured", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/download/info": {"get": {"summary": "Metadata for the BYOGPU worker ZIP (filename, size, sha256)", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Worker ZIP metadata", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "403": {"description": "BYOGPU subscription required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/download/zip": {"get": {"summary": "Download the BYOGPU worker ZIP bundle", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Worker ZIP archive", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "403": {"description": "BYOGPU subscription required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/workers": {"get": {"summary": "List BYOGPU workers registered to the authenticated account", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Worker list", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/workers/pair": {"post": {"summary": "Mint a one-shot 15-minute BYOGPU worker pairing code", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Pairing code + install command", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "403": {"description": "BYOGPU subscription required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/portal/api/byogpu/workers/revoke": {"post": {"summary": "Revoke a BYOGPU worker registration", "tags": ["portal", "byogpu"], "responses": {"200": {"description": "Worker revoked", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuccessResponse"}}}}, "400": {"description": "Invalid worker id", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"description": "Authentication required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"description": "Worker not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}}}