{
  "openapi": "3.0.3",
  "info": {
    "title": "The Delegation API",
    "version": "1.0.0",
    "description": "The Delegation exposes two APIs:\n\n**AI Gateway** — OpenAI-compatible proxy that routes to Claude, OpenAI, and Gemini.\nAuthenticate with a gateway key (`gw-…`) from your developer dashboard.\n\n**Platform API** — REST resources for projects, tasks, conversations, files, sessions,\nand user management. Authenticate with a session `access_token` (Bearer).\n",
    "contact": {
      "url": "https://delegation.malcolmstone.io",
      "email": "support@thedelegation.ai"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://gateway.malcolmstone.io"
    },
    {
      "url": "http://local.gateway.malcolmstone.io",
      "description": "AI Gateway (OpenAI-compatible)"
    },
    {
      "url": "https://delegation.malcolmstone.io",
      "description": "Platform API"
    }
  ],
  "tags": [
    {
      "name": "Gateway",
      "description": "OpenAI-compatible AI proxy endpoints"
    },
    {
      "name": "Projects",
      "description": "Project management"
    },
    {
      "name": "Teams",
      "description": "Agent teams within a project"
    },
    {
      "name": "Tasks",
      "description": "Agent task management"
    },
    {
      "name": "Conversations",
      "description": "Project conversation threads"
    },
    {
      "name": "Results",
      "description": "Agent output results"
    },
    {
      "name": "Files",
      "description": "User file storage"
    },
    {
      "name": "Sessions",
      "description": "Gateway session tracking — group requests by session ID"
    },
    {
      "name": "Keys",
      "description": "Gateway API key management"
    },
    {
      "name": "Users",
      "description": "Admin-scoped user management (read, update, delete, balance, restore)"
    },
    {
      "name": "Auth",
      "description": "CLI authentication — login, token refresh, logout"
    },
    {
      "name": "Account",
      "description": "Authenticated user account management"
    }
  ],
  "components": {
    "securitySchemes": {
      "GatewayKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Gateway API key issued from the developer dashboard. Format: `gw-<key>`."
      },
      "SessionToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Session `access_token` from `POST /api/auth` (CLI/API clients) or `GET /api/auth/session` (browser)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "example": "Unauthorized"
          }
        }
      },
      "ChatMessage": {
        "type": "object",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "system",
              "user",
              "assistant",
              "tool"
            ]
          },
          "content": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "type": "object",
                      "required": [
                        "type",
                        "text"
                      ],
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "text"
                          ]
                        },
                        "text": {
                          "type": "string"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "type",
                        "image_url"
                      ],
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "image_url"
                          ]
                        },
                        "image_url": {
                          "type": "object",
                          "required": [
                            "url"
                          ],
                          "properties": {
                            "url": {
                              "type": "string"
                            },
                            "detail": {
                              "type": "string",
                              "enum": [
                                "auto",
                                "low",
                                "high"
                              ]
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "tool_calls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolCall"
            }
          },
          "tool_call_id": {
            "type": "string"
          }
        }
      },
      "ToolDefinition": {
        "type": "object",
        "required": [
          "type",
          "function"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "function"
            ]
          },
          "function": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "parameters": {
                "type": "object",
                "description": "JSON Schema for function arguments."
              }
            }
          }
        }
      },
      "ToolCall": {
        "type": "object",
        "required": [
          "id",
          "type",
          "function"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "function"
            ]
          },
          "function": {
            "type": "object",
            "required": [
              "name",
              "arguments"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "arguments": {
                "type": "string",
                "description": "JSON-serialised function arguments."
              }
            }
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": [
          "model",
          "messages"
        ],
        "properties": {
          "model": {
            "type": "string",
            "example": "claude-sonnet-4-6",
            "description": "Model ID. See GET /v1/models for the full list."
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "stream": {
            "type": "boolean",
            "default": false
          },
          "max_tokens": {
            "type": "integer",
            "description": "Maximum generated tokens."
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "default": 1
          },
          "top_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "stop": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "system": {
            "type": "string",
            "description": "Shorthand system prompt."
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolDefinition"
            }
          },
          "tool_choice": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "auto",
                  "none",
                  "required"
                ]
              },
              {
                "type": "object",
                "required": [
                  "type",
                  "function"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "function"
                    ]
                  },
                  "function": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            ]
          },
          "provider": {
            "type": "string",
            "enum": [
              "claude",
              "openai",
              "gemini",
              "auto"
            ],
            "description": "Preferred provider. auto routes to cheapest."
          },
          "n": {
            "type": "integer",
            "minimum": 1,
            "maximum": 128,
            "default": 1
          }
        }
      },
      "ChatCompletionResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "chatcmpl-abc123"
          },
          "object": {
            "type": "string",
            "enum": [
              "chat.completion"
            ]
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "$ref": "#/components/schemas/ChatMessage"
                },
                "finish_reason": {
                  "type": "string",
                  "enum": [
                    "stop",
                    "length",
                    "tool_calls",
                    "content_filter"
                  ]
                }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": {
                "type": "integer"
              },
              "completion_tokens": {
                "type": "integer"
              },
              "total_tokens": {
                "type": "integer"
              }
            }
          }
        }
      },
      "EmbeddingRequest": {
        "type": "object",
        "required": [
          "input",
          "model"
        ],
        "properties": {
          "input": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "model": {
            "type": "string",
            "example": "text-embedding-3-small"
          },
          "dimensions": {
            "type": "integer",
            "description": "Reduce output dimensions (model-dependent, max 3072)."
          },
          "encoding_format": {
            "type": "string",
            "enum": [
              "float",
              "base64"
            ],
            "default": "float"
          }
        }
      },
      "ImageGenRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string"
          },
          "model": {
            "type": "string",
            "default": "dall-e-3",
            "enum": [
              "dall-e-3",
              "dall-e-2",
              "gemini-2.5-flash"
            ]
          },
          "n": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "default": 1
          },
          "size": {
            "type": "string",
            "enum": [
              "256x256",
              "512x512",
              "1024x1024",
              "1024x1792",
              "1792x1024"
            ],
            "default": "1024x1024"
          },
          "quality": {
            "type": "string",
            "enum": [
              "standard",
              "hd"
            ],
            "default": "standard"
          },
          "style": {
            "type": "string",
            "enum": [
              "natural",
              "vivid"
            ],
            "description": "DALL-E 3 only."
          },
          "response_format": {
            "type": "string",
            "enum": [
              "url",
              "b64_json"
            ],
            "default": "url"
          }
        }
      },
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "team_type": {
            "type": "string",
            "enum": [
              "software-development",
              "content-creation",
              "research",
              "custom"
            ]
          },
          "color": {
            "type": "string",
            "example": "#6366f1"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Task": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "running",
              "done",
              "failed",
              "waiting_approval"
            ]
          },
          "assigned_agent_id": {
            "type": "integer",
            "nullable": true
          },
          "requires_user_approval": {
            "type": "boolean"
          },
          "output": {
            "type": "string",
            "nullable": true
          },
          "draft_output": {
            "type": "string",
            "nullable": true
          },
          "review_comments": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant",
              "system"
            ]
          },
          "text": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Conversation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            }
          }
        }
      },
      "UserFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "display_name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "size_bytes": {
            "type": "integer"
          },
          "is_public": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "CDN URL (public files) or signed URL (private files)."
          },
          "storage_key": {
            "type": "string"
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GatewayKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "Full key value — returned only on creation, cannot be retrieved again.",
            "example": "gw-abc123"
          },
          "rate_limit": {
            "type": "integer",
            "description": "Requests per minute."
          },
          "revoked": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "developer",
              "admin"
            ]
          },
          "provider": {
            "type": "string"
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UserBalance": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "credit_coins": {
            "type": "integer",
            "description": "K-token credits (1 unit = 1,000 tokens)."
          },
          "storage_gb": {
            "type": "integer",
            "description": "File storage quota in GB."
          },
          "extra_projects": {
            "type": "integer",
            "description": "Additional project slots beyond the plan default."
          },
          "extra_agents": {
            "type": "integer",
            "description": "Additional agent slots beyond the plan default."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AuthSession": {
        "type": "object",
        "description": "Returned by POST /api/auth and PUT /api/auth.",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "JWT — pass as `Authorization: Bearer` on every request."
          },
          "refresh_token": {
            "type": "string",
            "description": "Opaque token — store securely, use to obtain a new access_token when expired."
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until the access_token expires."
          },
          "expires_at": {
            "type": "integer",
            "nullable": true,
            "description": "Unix timestamp of expiry."
          },
          "user": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "email": {
                "type": "string",
                "format": "email",
                "nullable": true
              },
              "metadata": {
                "type": "object"
              }
            }
          }
        }
      },
      "Session": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Use this value as the X-Session-ID header on gateway requests."
          },
          "user_id": {
            "type": "string",
            "description": "ID (users.id) of the owning user."
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "prompt_tokens": {
            "type": "integer",
            "description": "Accumulated prompt tokens across all requests in the session."
          },
          "completion_tokens": {
            "type": "integer",
            "description": "Accumulated completion tokens."
          },
          "total_tokens": {
            "type": "integer",
            "description": "Accumulated total tokens."
          },
          "request_count": {
            "type": "integer",
            "description": "Number of gateway requests attributed to this session."
          },
          "cost_usd": {
            "type": "number",
            "description": "Accumulated USD cost."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "Arbitrary key/value data attached at creation time."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid bearer token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "You don't have permission to access this resource.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid request body or parameters.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "Internal server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NoContent": {
        "description": "Success — no body returned."
      }
    }
  },
  "paths": {
    "/v1/chat/completions": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "summary": "Create chat completion",
        "description": "Generate the next assistant message given a conversation history. Supports streaming, function calling, and vision (multimodal content arrays).\n",
        "operationId": "createChatCompletion",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Session-ID",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Groups multiple requests into one session."
          },
          {
            "name": "X-Conversation-ID",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Associates the request with a conversation."
          },
          {
            "name": "X-Task-ID",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Tags the request to a specific task."
          },
          {
            "name": "X-Project-ID",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Tags the request to a project."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Chat completion or SSE stream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-Sent Events stream. Each line: `data: {chunk}`. Ends with `data: [DONE]`."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate limit exceeded. Respect `Retry-After` header."
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "Upstream AI provider error."
          }
        }
      }
    },
    "/v1/embeddings": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "summary": "Create embeddings",
        "description": "Convert text into dense vector representations.",
        "operationId": "createEmbeddings",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbeddingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Embedding vectors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "object": {
                            "type": "string",
                            "enum": [
                              "embedding"
                            ]
                          },
                          "index": {
                            "type": "integer"
                          },
                          "embedding": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    },
                    "model": {
                      "type": "string"
                    },
                    "usage": {
                      "type": "object",
                      "properties": {
                        "prompt_tokens": {
                          "type": "integer"
                        },
                        "total_tokens": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/images/generations": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "summary": "Generate images",
        "description": "Generate images from a text prompt via DALL-E or Gemini.",
        "operationId": "createImage",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImageGenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated images.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "b64_json": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/audio/speech": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "summary": "Text to speech",
        "description": "Synthesise speech audio from text using TTS-1 or TTS-1-HD.",
        "operationId": "createSpeech",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input",
                  "model"
                ],
                "properties": {
                  "input": {
                    "type": "string",
                    "maxLength": 4096
                  },
                  "model": {
                    "type": "string",
                    "enum": [
                      "tts-1",
                      "tts-1-hd"
                    ]
                  },
                  "voice": {
                    "type": "string",
                    "enum": [
                      "alloy",
                      "echo",
                      "fable",
                      "onyx",
                      "nova",
                      "shimmer"
                    ]
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "mp3",
                      "opus",
                      "aac",
                      "flac",
                      "wav"
                    ],
                    "default": "mp3"
                  },
                  "speed": {
                    "type": "number",
                    "minimum": 0.25,
                    "maximum": 4,
                    "default": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Binary audio stream.",
            "content": {
              "audio/mpeg": {},
              "audio/ogg": {},
              "audio/aac": {}
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/audio/transcriptions": {
      "post": {
        "tags": [
          "Gateway"
        ],
        "summary": "Speech to text",
        "description": "Transcribe audio to text using Whisper.",
        "operationId": "createTranscription",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "model"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file (max 25 MB). Supported: mp3, mp4, mpeg, mpga, m4a, wav, webm."
                  },
                  "model": {
                    "type": "string",
                    "enum": [
                      "whisper-1"
                    ]
                  },
                  "language": {
                    "type": "string",
                    "description": "ISO-639-1 language hint."
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Context hint to improve accuracy."
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "text",
                      "srt",
                      "vtt"
                    ],
                    "default": "json"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transcription text.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "tags": [
          "Gateway"
        ],
        "summary": "List models",
        "description": "Returns all available models with capabilities and pricing metadata.",
        "operationId": "listModels",
        "security": [
          {
            "GatewayKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Model list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string",
                      "enum": [
                        "list"
                      ]
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "object": {
                            "type": "string",
                            "enum": [
                              "model"
                            ]
                          },
                          "provider": {
                            "type": "string"
                          },
                          "capabilities": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List projects",
        "description": "Returns all projects owned by the authenticated user, newest first.",
        "operationId": "listProjects",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Project array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create project",
        "operationId": "createProject",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "teamType": {
                    "type": "string",
                    "enum": [
                      "software-development",
                      "content-creation",
                      "research",
                      "custom"
                    ]
                  },
                  "color": {
                    "type": "string",
                    "example": "#6366f1"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/projects/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Get project",
        "operationId": "getProject",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Projects"
        ],
        "summary": "Update project",
        "description": "Partial update — pass only the fields to change.",
        "operationId": "updateProject",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "teamType": {
                    "type": "string"
                  },
                  "color": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete project",
        "description": "Permanently deletes the project and all child data.",
        "operationId": "deleteProject",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/tasks": {
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Create task",
        "operationId": "createTask",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId",
                  "title"
                ],
                "properties": {
                  "projectId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "title": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "assignedAgentId": {
                    "type": "integer"
                  },
                  "requiresUserApproval": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created task.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Project not found or not owned by you."
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/tasks/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get task",
        "operationId": "getTask",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Task.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update task",
        "operationId": "updateTask",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "scheduled",
                      "running",
                      "done",
                      "failed",
                      "waiting_approval"
                    ]
                  },
                  "output": {
                    "type": "string"
                  },
                  "draft_output": {
                    "type": "string"
                  },
                  "review_comments": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated task.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/tasks/{id}/revisions": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "List task revisions",
        "description": "Returns the full revision history for a task.",
        "operationId": "listTaskRevisions",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Revision array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "task_id": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "output": {
                        "type": "string"
                      },
                      "created_at": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/tasks/{id}/status": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get task status",
        "description": "Lightweight polling endpoint — returns only the task status.",
        "operationId": "getTaskStatus",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Task status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "scheduled",
                        "running",
                        "done",
                        "failed",
                        "waiting_approval"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/conversations/{projectId}": {
      "parameters": [
        {
          "name": "projectId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Conversations"
        ],
        "summary": "Get conversation",
        "description": "Returns the conversation with all messages, ordered chronologically.",
        "operationId": "getConversation",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation with messages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Conversation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Conversations"
        ],
        "summary": "Clear conversation",
        "description": "Deletes all messages in the conversation. The conversation object is preserved.",
        "operationId": "clearConversation",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/api/conversations/{projectId}/messages": {
      "parameters": [
        {
          "name": "projectId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Conversations"
        ],
        "summary": "Send message",
        "operationId": "createMessage",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "role",
                  "text"
                ],
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "user",
                      "assistant",
                      "system"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Defaults to server time."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/user-files": {
      "get": {
        "tags": [
          "Files"
        ],
        "summary": "List files",
        "description": "Returns active files. Add `?trash=1` to list soft-deleted files.",
        "operationId": "listFiles",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "trash",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Set to 1 to list trashed files."
          }
        ],
        "responses": {
          "200": {
            "description": "File array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UserFile"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Files"
        ],
        "summary": "Upload file",
        "description": "Multipart form upload. Max 50 MB per file.",
        "operationId": "uploadFile",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "isPublic": {
                    "type": "string",
                    "enum": [
                      "true",
                      "false"
                    ],
                    "default": "false"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded file object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFile"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "tags": [
          "Files"
        ],
        "summary": "Update file",
        "description": "Rename a file or toggle its public/private visibility.",
        "operationId": "updateFile",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "action"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "rename",
                      "visibility"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "description": "New display name (action=rename)."
                  },
                  "isPublic": {
                    "type": "boolean",
                    "description": "New visibility (action=visibility)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFile"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Files"
        ],
        "summary": "Delete / trash file",
        "description": "Soft-deletes the file (recoverable within 30 days). Add `&permanent=1` to permanently delete immediately.",
        "operationId": "deleteFile",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "permanent",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Set to 1 for immediate permanent deletion."
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/user-files/recover": {
      "post": {
        "tags": [
          "Files"
        ],
        "summary": "Restore file from trash",
        "operationId": "recoverFile",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Restored file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFile"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/session": {
      "get": {
        "tags": [
          "Sessions"
        ],
        "summary": "Get or list sessions",
        "description": "With `?id={uuid}`: returns a single session owned by the caller.\nWithout `id`: returns all sessions for the caller, newest first.\n\nThe `id` of each session is the value to pass as the `X-Session-ID` header\non gateway requests you want attributed to that session.\n",
        "operationId": "getSession",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Session UUID. Omit to list all sessions."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": "Maximum sessions to return when listing."
          }
        ],
        "responses": {
          "200": {
            "description": "A single session object (when id is supplied) or an array of sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Session"
                    },
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Session"
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Sessions"
        ],
        "summary": "Create a session",
        "description": "Creates a new session and returns it. Use the returned `id` as the\n`X-Session-ID` header on every gateway request you want grouped under\nthis session. Token and cost totals accumulate via PUT /api/session.\n",
        "operationId": "createSession",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "Human-readable name for this session."
                  },
                  "metadata": {
                    "type": "object",
                    "description": "Arbitrary key/value data (model tags, project refs, etc.)."
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Optional TTL — must be in the future."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "tags": [
          "Sessions"
        ],
        "summary": "Update session tokens",
        "description": "Apply token / cost deltas (or set absolute values) for a session.\n\n**Increment mode** (default): each supplied field is *added* to the\nexisting total. Omitted fields are left unchanged.\n\n**Set mode**: each supplied field *replaces* the existing value.\n\nWhen `total_tokens` is omitted in increment mode, the route derives it\nautomatically as `prompt_tokens + completion_tokens`.\n\nTypically called server-side after each gateway response — the response\nbody includes the updated `usage` object you can forward directly.\n",
        "operationId": "updateSessionTokens",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Session to update."
                  },
                  "prompt_tokens": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Prompt tokens to apply."
                  },
                  "completion_tokens": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Completion tokens to apply."
                  },
                  "total_tokens": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Total tokens. Derived from prompt + completion if omitted in increment mode."
                  },
                  "request_count": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Number of requests to apply (default 1 when not supplied)."
                  },
                  "cost_usd": {
                    "type": "number",
                    "description": "USD cost to apply."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "increment",
                      "set"
                    ],
                    "default": "increment"
                  }
                }
              },
              "example": {
                "id": "550e8400-e29b-41d4-a716-446655440000",
                "prompt_tokens": 150,
                "completion_tokens": 220,
                "cost_usd": 0.00043,
                "mode": "increment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated session with new totals.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Session not found or not owned by caller."
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/users/gateway-keys": {
      "get": {
        "tags": [
          "Keys"
        ],
        "summary": "List gateway keys",
        "description": "Returns all keys (active and revoked). The raw key value is only returned on creation.",
        "operationId": "listGatewayKeys",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Key array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GatewayKey"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Keys"
        ],
        "summary": "Issue gateway key",
        "description": "Creates a new gateway key. The full key value is returned only in this response.",
        "operationId": "createGatewayKey",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Human-readable label, e.g. my-app-prod."
                  },
                  "rate_limit": {
                    "type": "integer",
                    "description": "Requests per minute. Defaults to plan limit."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New key — save the `key` value immediately.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "Keys"
        ],
        "summary": "Revoke gateway key",
        "description": "Immediately rejects all requests authenticated with this key. Irreversible.",
        "operationId": "revokeGatewayKey",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/users/gateway-usage": {
      "get": {
        "tags": [
          "Keys"
        ],
        "summary": "Gateway usage statistics",
        "description": "Returns total tokens, total cost (USD), and per-request usage records.",
        "operationId": "getGatewayUsage",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_tokens": {
                      "type": "integer"
                    },
                    "total_cost": {
                      "type": "number",
                      "description": "Total cost in USD."
                    },
                    "records": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "model": {
                            "type": "string"
                          },
                          "provider": {
                            "type": "string"
                          },
                          "prompt_tokens": {
                            "type": "integer"
                          },
                          "completion_tokens": {
                            "type": "integer"
                          },
                          "cost_usd": {
                            "type": "number"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/users": {
      "post": {
        "tags": [
          "Users"
        ],
        "summary": "Create user",
        "description": "Admin-only. Creates the user row (bcrypt-hashed password, email pre-verified).\n\n`role` is **required** — there is no default. All string fields must be\nnon-empty. `password` must be at least 8 characters. The account is\nautomatically email-confirmed so the user can sign in immediately via\n`POST /api/auth`.\n",
        "operationId": "createUser",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "first_name",
                  "last_name",
                  "email",
                  "username",
                  "password",
                  "role"
                ],
                "properties": {
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "minLength": 8
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "user",
                      "developer",
                      "admin"
                    ],
                    "description": "Required. No default."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Email or username already in use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "List users",
        "description": "Admin-only. Returns a paginated list of all platform users.\nSupports filtering by role, free-text prefix search on email/username,\nand optionally including soft-deleted accounts.\n",
        "operationId": "listUsers",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "role",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "user",
                "developer",
                "admin"
              ]
            },
            "description": "Filter by role."
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Prefix match on email or username."
          },
          {
            "name": "include_deleted",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Set to 1 to include soft-deleted accounts."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Maximum rows to return."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated user list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching records (ignores limit/offset)."
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/users/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "The users primary key."
        }
      ],
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get user",
        "description": "Returns the user record. Accessible by admin or the user themselves.\nPass `?include_deleted=1` (admin only) to retrieve soft-deleted accounts.\n",
        "operationId": "getUser",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "include_deleted",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Admin only — include soft-deleted accounts."
          }
        ],
        "responses": {
          "200": {
            "description": "User record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "tags": [
          "Users"
        ],
        "summary": "Update user",
        "description": "Partial update of a user record.\n\n- **Admin**: may set any field including `role`.\n- **Self** (non-admin): may set `first_name`, `last_name`, `username`, `password` only. Cannot set `role`.\n",
        "operationId": "updateUser",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "description": "New password (hashed server-side)."
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "user",
                      "developer",
                      "admin"
                    ],
                    "description": "Admin only."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "tags": [
          "Users"
        ],
        "summary": "Soft-delete user",
        "description": "Soft-deletes the user (sets `deleted_at`). Accessible by admin or the\nuser themselves. Admins cannot delete their own account via this endpoint\n— use `DELETE /api/account` instead.\n",
        "operationId": "deleteUser",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/users/{id}/balance": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "The public.users primary key."
        }
      ],
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get user balance",
        "description": "Admin-only. Returns the user's credit/storage/quota balance. Returns a zero-value object when no balance row exists yet.\n",
        "operationId": "getUserBalance",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "User balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserBalance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "tags": [
          "Users"
        ],
        "summary": "Update user balance",
        "description": "Admin-only. Adjust a user's credit coins, storage quota, or bonus slots.\n\n**mode: \"increment\"** (default) — adds the supplied delta to each field.\nNegative deltas are allowed to subtract.\n\n**mode: \"set\"** — replaces each field with the exact value supplied.\nValues cannot be negative in set mode.\n\nSupply at least one balance field.\n",
        "operationId": "updateUserBalance",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "credit_coins": {
                    "type": "integer",
                    "description": "K-token credits (1 = 1,000 tokens)."
                  },
                  "storage_gb": {
                    "type": "integer",
                    "description": "Storage quota in GB."
                  },
                  "extra_projects": {
                    "type": "integer",
                    "description": "Additional project slots."
                  },
                  "extra_agents": {
                    "type": "integer",
                    "description": "Additional agent slots."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "increment",
                      "set"
                    ],
                    "default": "increment"
                  }
                }
              },
              "examples": {
                "add_credits": {
                  "summary": "Add 100 K-token credits",
                  "value": {
                    "credit_coins": 100,
                    "mode": "increment"
                  }
                },
                "set_storage": {
                  "summary": "Set storage quota to 50 GB",
                  "value": {
                    "storage_gb": 50,
                    "mode": "set"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserBalance"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/users/{id}/restore": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "The public.users primary key."
        }
      ],
      "post": {
        "tags": [
          "Users"
        ],
        "summary": "Restore deleted user",
        "description": "Admin-only. Clears the `deleted_at` timestamp on a soft-deleted account,\nmaking it active again. Returns 404 if the account is not currently deleted.\n\nSessions revoked at deletion stay revoked; the user signs in again.\n",
        "operationId": "restoreUser",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Restored user record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "User not found or account is not deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/auth": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Login",
        "description": "Exchange an email + password for a session (access + refresh token).\n\nReturns `access_token` and `refresh_token`. Store both locally.\nPass `access_token` as `Authorization: Bearer <token>` on every\nsubsequent request. When it expires (see `expires_in`), call\n`PUT /api/auth` with the saved `refresh_token` to get a fresh pair.\n\nNo cookies are set — designed for CLI and non-browser clients.\n",
        "operationId": "login",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "format": "password"
                  }
                }
              },
              "example": {
                "email": "alice@example.com",
                "password": "hunter2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthSession"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "description": "Invalid email or password.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "Refresh session",
        "description": "Exchange a `refresh_token` for a new `access_token` + `refresh_token` pair. Use when the access token has expired.\n",
        "operationId": "refreshSession",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "refresh_token"
                ],
                "properties": {
                  "refresh_token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fresh session tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthSession"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "description": "Refresh token is invalid or expired — log in again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "Logout",
        "description": "Revokes the access token and its paired refresh token server-side. Requires `Authorization: Bearer <access_token>`.\n",
        "operationId": "logout",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get account",
        "description": "Returns the DB user record for the authenticated session. Auto-provisions a row if this is the first login.\n",
        "operationId": "getAccount",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "User record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "tags": [
          "Account"
        ],
        "summary": "Update account role",
        "description": "Switch between `user` and `developer` account types. Users may only switch to roles in the self-switchable set.\n",
        "operationId": "updateAccountRole",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "role"
                ],
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "user",
                      "developer"
                    ],
                    "description": "Target role."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated role.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "tags": [
          "Account"
        ],
        "summary": "Delete account",
        "description": "Soft-deletes the authenticated user's account (sets `deleted_at`). The session is revoked server-side; discard the tokens client-side.\n",
        "operationId": "deleteAccount",
        "security": [
          {
            "SessionToken": []
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  }
}