{"openapi": "3.1.0", "info": {"title": "ai-backend - Ifolor AI RPC/MCP Service", "version": "0.4.2rc1", "description": ""}, "paths": {"/api/actions": {"post": {"operationId": "server_apps_actions_api_views_execute_action", "summary": "Execute Action", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ActionResponse"}}}}, "202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AsyncActionResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "502": {"description": "Bad Gateway", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Execute an RPC-JSON action.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ActionRequest"}}}, "required": true}, "security": [{"APIKeyAuth": []}]}}, "/api/users/import": {"post": {"operationId": "server_apps_images_api_user_views_import_images", "summary": "Import Images", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "202": {"description": "Accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Create an import-user-images Job and fan it out.\n\nThe Job is the unit clients track: poll GET /api/jobs/{job_id} until\nits `children_summary` shows all per-image children settled.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ImportRequest"}}}, "required": true}, "security": [{"APIKeyAuth": []}]}}, "/api/jobs": {"get": {"operationId": "server_apps_jobs_api_views_list_jobs", "summary": "List Jobs", "parameters": [{"in": "query", "name": "status", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by status", "title": "Status"}, "required": false, "description": "Filter by status"}, {"in": "query", "name": "job_type", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by job type", "title": "Job Type"}, "required": false, "description": "Filter by job type"}, {"in": "query", "name": "created_after", "schema": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "description": "Filter jobs created after", "title": "Created After"}, "required": false, "description": "Filter jobs created after"}, {"in": "query", "name": "created_before", "schema": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "description": "Filter jobs created before", "title": "Created Before"}, "required": false, "description": "Filter jobs created before"}, {"in": "query", "name": "page", "schema": {"default": 1, "description": "Page number", "minimum": 1, "title": "Page", "type": "integer"}, "required": false, "description": "Page number"}, {"in": "query", "name": "page_size", "schema": {"default": 20, "description": "Items per page", "maximum": 100, "minimum": 1, "title": "Page Size", "type": "integer"}, "required": false, "description": "Items per page"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobListResponse"}}}}}, "description": "List jobs with filtering and pagination.", "security": [{"APIKeyAuth": []}]}}, "/api/jobs/{job_id}": {"get": {"operationId": "server_apps_jobs_api_views_get_job", "summary": "Get Job", "parameters": [{"in": "path", "name": "job_id", "schema": {"format": "uuid", "title": "Job Id", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Get a single job by ID.", "security": [{"APIKeyAuth": []}]}}, "/api/jobs/{job_id}/cancel": {"post": {"operationId": "server_apps_jobs_api_views_cancel_job", "summary": "Cancel Job", "parameters": [{"in": "path", "name": "job_id", "schema": {"format": "uuid", "title": "Job Id", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobCancelResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Request cancellation of a job.\n\nThis sends a revoke signal to the Celery task. The task will be cancelled\nif it hasn't started yet. For running tasks, they must check for\ncancellation cooperatively.", "security": [{"APIKeyAuth": []}]}}, "/api/subscriptions": {"post": {"operationId": "server_apps_jobs_api_subscriptions_create_subscription", "summary": "Create Subscription", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SubscriptionResponse"}}}}, "201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SubscriptionResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Create a new event subscription.\n\nTransports:\n- http: Events delivered via HTTP POST to target_url\n- websocket: Events delivered via WebSocket connection to target_url\n\nEvents:\n- job.created: When a new job is created\n- job.updated: When a job status changes\n- job.completed: When a job completes successfully\n- job.failed: When a job fails\n\nJobs filter:\n- [\"*\"]: Subscribe to all jobs\n- [\"job-id-1\", \"job-id-2\"]: Subscribe to specific jobs only", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SubscriptionCreateRequest"}}}, "required": true}, "security": [{"APIKeyAuth": []}]}, "get": {"operationId": "server_apps_jobs_api_subscriptions_list_subscriptions", "summary": "List Subscriptions", "parameters": [{"in": "query", "name": "transport", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by transport (http, websocket)", "title": "Transport"}, "required": false, "description": "Filter by transport (http, websocket)"}, {"in": "query", "name": "event", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by subscribed event", "title": "Event"}, "required": false, "description": "Filter by subscribed event"}, {"in": "query", "name": "job_id", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by job ID in subscription", "title": "Job Id"}, "required": false, "description": "Filter by job ID in subscription"}, {"in": "query", "name": "is_active", "schema": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "description": "Filter by active status", "title": "Is Active"}, "required": false, "description": "Filter by active status"}, {"in": "query", "name": "page", "schema": {"default": 1, "description": "Page number", "minimum": 1, "title": "Page", "type": "integer"}, "required": false, "description": "Page number"}, {"in": "query", "name": "page_size", "schema": {"default": 20, "description": "Items per page", "maximum": 100, "minimum": 1, "title": "Page Size", "type": "integer"}, "required": false, "description": "Items per page"}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SubscriptionListResponse"}}}}}, "description": "List all subscriptions with optional filters.", "security": [{"APIKeyAuth": []}]}}, "/api/subscriptions/{subscription_id}": {"get": {"operationId": "server_apps_jobs_api_subscriptions_get_subscription", "summary": "Get Subscription", "parameters": [{"in": "path", "name": "subscription_id", "schema": {"format": "uuid", "title": "Subscription Id", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SubscriptionResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Get a subscription by ID.", "security": [{"APIKeyAuth": []}]}, "delete": {"operationId": "server_apps_jobs_api_subscriptions_delete_subscription", "summary": "Delete Subscription", "parameters": [{"in": "path", "name": "subscription_id", "schema": {"format": "uuid", "title": "Subscription Id", "type": "string"}, "required": true}], "responses": {"204": {"description": "No Content"}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Delete a subscription.", "security": [{"APIKeyAuth": []}]}}, "/api/workflows/{workflow_id}/cancel": {"post": {"operationId": "server_apps_images_api_workflow_views_cancel_workflow", "summary": "Cancel Workflow", "parameters": [{"in": "path", "name": "workflow_id", "schema": {"format": "uuid", "title": "Workflow Id", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCancelResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}, "description": "Cancel a running workflow and revoke its branch tasks.", "security": [{"APIKeyAuth": []}]}}}, "components": {"schemas": {"ActionResponse": {"description": "RPC-JSON action response.", "properties": {"action": {"title": "Action", "type": "string"}, "result": {"additionalProperties": true, "title": "Result", "type": "object"}}, "required": ["action", "result"], "title": "ActionResponse", "type": "object"}, "AsyncActionResponse": {"description": "Response for async actions (202 Accepted).", "properties": {"action": {"title": "Action", "type": "string"}, "job_id": {"title": "Job Id", "type": "string"}, "status": {"title": "Status", "type": "string"}}, "required": ["action", "job_id", "status"], "title": "AsyncActionResponse", "type": "object"}, "ErrorResponse": {"description": "Error response schema.", "properties": {"detail": {"title": "Detail", "type": "string"}}, "required": ["detail"], "title": "ErrorResponse", "type": "object"}, "ActionRequest": {"description": "RPC-JSON action request.", "properties": {"user_id": {"maxLength": 255, "minLength": 1, "title": "User Id", "type": "string"}, "action": {"$ref": "#/components/schemas/ActionType"}, "params": {"additionalProperties": true, "title": "Params", "type": "object"}}, "required": ["user_id", "action", "params"], "title": "ActionRequest", "type": "object"}, "ActionType": {"description": "Supported RPC action types.", "enum": ["SUGGEST_TEXT", "SUGGEST_ALTERNATIVE_IMAGES", "DETECT_DUPLICATES", "SUGGEST_PHOTOBOOK"], "title": "ActionType", "type": "string"}, "JobChildrenSummary": {"description": "Aggregated status of a parent job's children.\n\nPopulated only for jobs that have at least one child (currently\n`import_user_images` jobs; the four bucket counts sum to `total`).", "properties": {"total": {"title": "Total", "type": "integer"}, "pending": {"title": "Pending", "type": "integer"}, "processing": {"title": "Processing", "type": "integer"}, "completed": {"title": "Completed", "type": "integer"}, "failed": {"title": "Failed", "type": "integer"}}, "required": ["total", "pending", "processing", "completed", "failed"], "title": "JobChildrenSummary", "type": "object"}, "JobResponse": {"description": "Response schema for a single job.", "properties": {"id": {"format": "uuid", "title": "Id", "type": "string"}, "parent_id": {"anyOf": [{"format": "uuid", "type": "string"}, {"type": "null"}], "title": "Parent Id"}, "celery_task_id": {"title": "Celery Task Id", "type": "string"}, "celery_task_name": {"title": "Celery Task Name", "type": "string"}, "job_type": {"title": "Job Type", "type": "string"}, "status": {"title": "Status", "type": "string"}, "progress_percent": {"title": "Progress Percent", "type": "integer"}, "progress_message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Progress Message"}, "result": {"anyOf": [{"additionalProperties": true, "type": "object"}, {"type": "null"}], "title": "Result"}, "error_message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error Message"}, "queue": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Queue"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "started_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Started At"}, "completed_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Completed At"}, "processing_time_ms": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Processing Time Ms"}, "retry_count": {"title": "Retry Count", "type": "integer"}, "cancellation_requested": {"title": "Cancellation Requested", "type": "boolean"}, "metadata": {"additionalProperties": true, "title": "Metadata", "type": "object"}, "children_summary": {"anyOf": [{"$ref": "#/components/schemas/JobChildrenSummary"}, {"type": "null"}]}}, "required": ["id", "celery_task_id", "celery_task_name", "job_type", "status", "progress_percent", "progress_message", "result", "error_message", "queue", "created_at", "updated_at", "started_at", "completed_at", "processing_time_ms", "retry_count", "cancellation_requested", "metadata"], "title": "JobResponse", "type": "object"}, "ImageDownloadInfoIn": {"description": "SAS download URI minted by the CLI.\n\nEmbedded in the /users/import request body; the worker uses this\nlist directly \u2014 the server itself never calls IM for the import\npath.", "properties": {"original_image_id": {"title": "Original Image Id", "type": "string"}, "download_uri": {"title": "Download Uri", "type": "string"}, "uploaded_at": {"default": "", "title": "Uploaded At", "type": "string"}, "derivative_created_at": {"default": "", "title": "Derivative Created At", "type": "string"}, "metadata": {"additionalProperties": {"type": "string"}, "default": {}, "title": "Metadata", "type": "object"}}, "required": ["original_image_id", "download_uri"], "title": "ImageDownloadInfoIn", "type": "object"}, "ImportRequest": {"description": "Request body for user import endpoint.", "properties": {"data_source": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Data Source"}, "user_id": {"maxLength": 255, "minLength": 1, "title": "User Id", "type": "string"}, "source_type": {"default": "minio", "title": "Source Type", "type": "string"}, "image_ids": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Image Ids"}, "image_type": {"default": "Original", "title": "Image Type", "type": "string"}, "image_download_infos": {"anyOf": [{"items": {"$ref": "#/components/schemas/ImageDownloadInfoIn"}, "type": "array"}, {"type": "null"}], "title": "Image Download Infos"}}, "required": ["user_id"], "title": "ImportRequest", "type": "object"}, "JobListResponse": {"description": "Response schema for job list.", "properties": {"items": {"items": {"$ref": "#/components/schemas/JobResponse"}, "title": "Items", "type": "array"}, "total": {"title": "Total", "type": "integer"}, "page": {"title": "Page", "type": "integer"}, "page_size": {"title": "Page Size", "type": "integer"}}, "required": ["items", "total", "page", "page_size"], "title": "JobListResponse", "type": "object"}, "JobCancelResponse": {"description": "Response schema for cancellation.", "properties": {"id": {"format": "uuid", "title": "Id", "type": "string"}, "status": {"title": "Status", "type": "string"}, "cancellation_requested": {"title": "Cancellation Requested", "type": "boolean"}, "message": {"title": "Message", "type": "string"}}, "required": ["id", "status", "cancellation_requested", "message"], "title": "JobCancelResponse", "type": "object"}, "SubscriptionResponse": {"description": "Response schema for a subscription.", "properties": {"id": {"format": "uuid", "title": "Id", "type": "string"}, "target_url": {"title": "Target Url", "type": "string"}, "transport": {"title": "Transport", "type": "string"}, "jobs": {"items": {"type": "string"}, "title": "Jobs", "type": "array"}, "events": {"items": {"type": "string"}, "title": "Events", "type": "array"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "is_active": {"title": "Is Active", "type": "boolean"}, "expires_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Expires At"}, "consecutive_failures": {"title": "Consecutive Failures", "type": "integer"}, "disabled_reason": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Disabled Reason"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "target_url", "transport", "jobs", "events", "description", "is_active", "expires_at", "consecutive_failures", "disabled_reason", "created_at", "updated_at"], "title": "SubscriptionResponse", "type": "object"}, "SubscriptionCreateRequest": {"description": "Request schema for creating a subscription.", "properties": {"target_url": {"title": "Target Url", "type": "string"}, "transport": {"default": "http", "title": "Transport", "type": "string"}, "jobs": {"default": ["*"], "items": {"type": "string"}, "title": "Jobs", "type": "array"}, "events": {"items": {"type": "string"}, "title": "Events", "type": "array"}, "secret": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "is_active": {"default": true, "title": "Is Active", "type": "boolean"}, "ttl": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Ttl"}, "expires_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Expires At"}}, "required": ["target_url", "events"], "title": "SubscriptionCreateRequest", "type": "object"}, "SubscriptionListResponse": {"description": "Response schema for subscription list.", "properties": {"items": {"items": {"$ref": "#/components/schemas/SubscriptionResponse"}, "title": "Items", "type": "array"}, "total": {"title": "Total", "type": "integer"}, "page": {"title": "Page", "type": "integer"}, "page_size": {"title": "Page Size", "type": "integer"}}, "required": ["items", "total", "page", "page_size"], "title": "SubscriptionListResponse", "type": "object"}, "WorkflowCancelResponse": {"description": "Response schema for workflow cancellation.", "properties": {"id": {"format": "uuid", "title": "Id", "type": "string"}, "status": {"title": "Status", "type": "string"}, "message": {"title": "Message", "type": "string"}}, "required": ["id", "status", "message"], "title": "WorkflowCancelResponse", "type": "object"}}, "securitySchemes": {"APIKeyAuth": {"type": "apiKey", "in": "header", "name": "X-API-Key"}}}, "servers": []}