{
  "openapi": "3.1.0",
  "info": {
    "title": "Raven API (stub for frontend development)",
    "description": "Stub contract used by the frontend stream during parallel development.\nReflects the real API shape that the backend stream will implement.\nReplace with real OpenAPI spec once backend PRs merge.\n",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "Local dev"
    }
  ],
  "tags": [
    {
      "name": "Organizations",
      "description": "Organization lifecycle and membership."
    },
    {
      "name": "Workspaces",
      "description": "Workspace lifecycle and membership inside an organization."
    },
    {
      "name": "KnowledgeBases",
      "description": "Knowledge base lifecycle inside a workspace."
    },
    {
      "name": "Users",
      "description": "Authenticated user profile endpoints."
    },
    {
      "name": "Search",
      "description": "Full-text and hybrid retrieval over knowledge-base chunks."
    },
    {
      "name": "Marketplace",
      "description": "Cross-tenant discovery surface for Public KBs. Authenticated User\nendpoints for listing, previewing, importing, publishing, and\nunpublishing. See ADR-0001, ADR-0002, ADR-0007.\n"
    },
    {
      "name": "Marketplace Admin",
      "description": "Admin-only moderation surface: report queue, takedown actions, and\nthe DMCA counter-notice intake. See ADR-0006.\n"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "Organization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "deactivated"
            ]
          },
          "settings": {
            "type": "object"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "status",
          "created_at",
          "updated_at"
        ]
      },
      "CreateOrgRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateOrgRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255
          },
          "settings": {
            "type": "object"
          }
        }
      },
      "OrgMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "org_role": {
            "type": "string",
            "enum": [
              "org_admin",
              "member"
            ]
          },
          "joined_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "user_id",
          "email",
          "org_role"
        ]
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "settings": {
            "type": "object"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "slug",
          "created_at",
          "updated_at"
        ]
      },
      "CreateWorkspaceRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255
          }
        },
        "required": [
          "name"
        ]
      },
      "WorkspaceMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "workspace_role": {
            "type": "string",
            "enum": [
              "owner",
              "admin",
              "member",
              "viewer"
            ]
          }
        },
        "required": [
          "user_id",
          "email",
          "workspace_role"
        ]
      },
      "KnowledgeBase": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "settings": {
            "type": "object"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "archived"
            ]
          },
          "doc_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "org_id",
          "workspace_id",
          "name",
          "slug",
          "status",
          "created_at",
          "updated_at"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "username": {
            "type": "string"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "org_role": {
            "type": "string",
            "enum": [
              "org_admin",
              "member"
            ]
          }
        },
        "required": [
          "id",
          "email",
          "org_id",
          "org_role"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "PaginatedList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {}
          },
          "total": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          }
        },
        "required": [
          "items",
          "total"
        ]
      },
      "HybridSearchRequest": {
        "type": "object",
        "description": "Request body for hybrid (vector + BM25) search. `embedding` is the\npre-computed query embedding for the vector leg; omit it to fall\nback to BM25-only ranking.\n",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "description": "The user query. Required and non-empty."
          },
          "top_k": {
            "type": "integer",
            "minimum": 0,
            "description": "Maximum number of fused results to return. `0` or omitted means\nthe server applies `retrieval.default_limit`. Values above\n`retrieval.max_limit` are clamped server-side (no 400).\n"
          },
          "filters": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Free-form metadata filter bag. Today only honoured downstream\n(e.g. `rerank: cohere` on the chat path); the standalone\nendpoint does not yet push predicates into SQL.\n"
          },
          "doc_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Restrict search to these document IDs."
          },
          "embedding": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "float"
            },
            "description": "Pre-computed query embedding. Length must match the configured\nembedding dimension (1536 by default). Empty array disables\nthe vector leg — RRF degrades to BM25-only.\n"
          }
        },
        "required": [
          "query"
        ]
      },
      "HybridSearchResult": {
        "type": "object",
        "description": "Single chunk returned from a hybrid search, carrying both per-leg\nscores and the fused Reciprocal Rank Fusion (RRF) score.\n",
        "properties": {
          "chunk_id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "knowledge_base_id": {
            "type": "string",
            "format": "uuid"
          },
          "document_id": {
            "type": "string",
            "format": "uuid"
          },
          "source_id": {
            "type": "string",
            "format": "uuid"
          },
          "content": {
            "type": "string"
          },
          "chunk_index": {
            "type": "integer"
          },
          "token_count": {
            "type": "integer"
          },
          "page_number": {
            "type": "integer"
          },
          "heading": {
            "type": "string"
          },
          "chunk_type": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "vector_score": {
            "type": "number",
            "format": "float",
            "description": "Cosine similarity in [0, 1]"
          },
          "bm25_score": {
            "type": "number",
            "format": "float",
            "description": "PostgreSQL ts_rank_cd score"
          },
          "rrf_score": {
            "type": "number",
            "format": "float",
            "description": "Fused RRF score"
          },
          "vector_rank": {
            "type": "integer",
            "description": "1-based rank in the vector leg; 0 if absent"
          },
          "bm25_rank": {
            "type": "integer",
            "description": "1-based rank in the BM25 leg; 0 if absent"
          }
        },
        "required": [
          "chunk_id",
          "org_id",
          "knowledge_base_id",
          "content",
          "chunk_index",
          "chunk_type",
          "created_at",
          "rrf_score"
        ]
      },
      "HybridSearchResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HybridSearchResult"
            }
          },
          "query": {
            "type": "string",
            "description": "Server-side trimmed echo of the requested query."
          },
          "top_k": {
            "type": "integer",
            "description": "Effective top_k after server-side clamping."
          }
        },
        "required": [
          "results",
          "query",
          "top_k"
        ]
      },
      "MarketplaceListItem": {
        "type": "object",
        "description": "Card-shape row for the Marketplace listing. Returned by the\n`marketplace_list_public_kbs()` SECURITY DEFINER function and any\nper-User filtering applied above it. `source_*` fields are\npopulated when this Public KB was itself imported from another\nPublic KB (one-hop lineage; see ADR-0001).\n",
        "properties": {
          "kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "org_slug": {
            "type": "string"
          },
          "org_display_name": {
            "type": "string"
          },
          "kb_slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "last_modified_at": {
            "type": "string",
            "format": "date-time"
          },
          "license_spdx_id": {
            "type": "string",
            "description": "SPDX id from the 7-item allow-list (ADR-0006)."
          },
          "import_count": {
            "type": "integer",
            "minimum": 0
          },
          "source_public_kb_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "source_org_slug": {
            "type": "string",
            "nullable": true
          },
          "source_org_display_name": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "kb_id",
          "org_slug",
          "org_display_name",
          "kb_slug",
          "name",
          "last_modified_at",
          "license_spdx_id",
          "import_count"
        ]
      },
      "MarketplaceListing": {
        "type": "object",
        "description": "Paginated Marketplace listing response. `next_cursor` is opaque;\ncallers must treat it as a black-box string to be echoed back.\n",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketplaceListItem"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true
          },
          "total": {
            "type": "integer",
            "description": "Total matching rows when cheaply computable; omitted otherwise."
          }
        },
        "required": [
          "items"
        ]
      },
      "PreviewChunk": {
        "type": "object",
        "description": "Single sample Chunk returned by the Marketplace preview surface\n(ADR-0007). Backed by `marketplace_preview_kb()`; the function\ncaps the response at three rows.\n",
        "properties": {
          "chunk_id": {
            "type": "string",
            "format": "uuid"
          },
          "ordinal": {
            "type": "integer",
            "minimum": 0
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "chunk_id",
          "ordinal",
          "text"
        ]
      },
      "MarketplacePreview": {
        "type": "object",
        "properties": {
          "chunks": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "$ref": "#/components/schemas/PreviewChunk"
            }
          }
        },
        "required": [
          "chunks"
        ]
      },
      "PublishRequest": {
        "type": "object",
        "description": "Body for `POST /knowledge_bases/{id}/publish`. The license must be\none of the seven SPDX ids in the allow-list (ADR-0006); requests\ncarrying any other value return 422.\n",
        "properties": {
          "license_spdx_id": {
            "type": "string",
            "description": "SPDX id from the 7-item allow-list (e.g. `CC-BY-4.0`)."
          }
        },
        "required": [
          "license_spdx_id"
        ]
      },
      "ReImportRequest": {
        "type": "object",
        "description": "Body for `POST /knowledge_bases/{id}/re-import`. The explicit\n`confirm` flag guards against accidental destructive overwrites\nof locally-edited Imported KB content (ADR-0001 fork semantics).\n",
        "properties": {
          "confirm": {
            "type": "boolean",
            "description": "Must be `true` to acknowledge the destructive re-fork."
          }
        },
        "required": [
          "confirm"
        ]
      },
      "ImportRequest": {
        "type": "object",
        "description": "Body for `POST /marketplace/import/{public_kb_id}`. The Importer\nchooses which Workspace inside their Org will own the new KB row;\nFree Plan Orgs have visibility forced to `public` per ADR-0004.\n",
        "properties": {
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "workspace_id"
        ]
      },
      "ImportResult": {
        "type": "object",
        "properties": {
          "kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "imported_from_revision_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "kb_id",
          "imported_from_revision_at"
        ]
      },
      "ReportRequest": {
        "type": "object",
        "description": "Submit a moderation Report against a Public KB. Per-User rate\nlimited; abuse returns 429.\n",
        "properties": {
          "kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          }
        },
        "required": [
          "kb_id",
          "reason"
        ]
      },
      "MarketplaceReport": {
        "type": "object",
        "properties": {
          "report_id": {
            "type": "string",
            "format": "uuid"
          },
          "reported_kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "reporter_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "reason": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "reviewing",
              "resolved",
              "dismissed"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "report_id",
          "reported_kb_id",
          "reason",
          "status",
          "created_at"
        ]
      },
      "DMCANotice": {
        "type": "object",
        "description": "DMCA takedown notice intake. Receipt queues the notice for the\n14-day counter-notice window before the target KB is unpublished\n(ADR-0006).\n",
        "properties": {
          "target_kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "notice": {
            "type": "string",
            "minLength": 1,
            "description": "Full text of the DMCA notice as submitted."
          }
        },
        "required": [
          "target_kb_id",
          "notice"
        ]
      },
      "DMCANoticeReceipt": {
        "type": "object",
        "properties": {
          "notice_id": {
            "type": "string",
            "format": "uuid"
          },
          "target_kb_id": {
            "type": "string",
            "format": "uuid"
          },
          "counter_notice_due": {
            "type": "string",
            "format": "date-time",
            "description": "14 days from receipt."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "counter_noticed",
              "executed",
              "withdrawn"
            ]
          }
        },
        "required": [
          "notice_id",
          "target_kb_id",
          "counter_notice_due",
          "status"
        ]
      }
    }
  },
  "paths": {
    "/orgs": {
      "post": {
        "summary": "Create organization",
        "operationId": "createOrganization",
        "tags": [
          "Organizations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrgRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/orgs/{org_id}": {
      "get": {
        "summary": "Get organization",
        "operationId": "getOrganization",
        "tags": [
          "Organizations"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Update organization",
        "operationId": "updateOrganization",
        "tags": [
          "Organizations"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateOrgRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Soft-delete organization",
        "operationId": "deleteOrganization",
        "tags": [
          "Organizations"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          }
        }
      }
    },
    "/orgs/{org_id}/members": {
      "get": {
        "summary": "List organization members",
        "operationId": "listOrganizationMembers",
        "tags": [
          "Organizations"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OrgMember"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/orgs/{org_id}/workspaces": {
      "get": {
        "summary": "List workspaces",
        "operationId": "listWorkspaces",
        "tags": [
          "Workspaces"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedList"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create workspace",
        "operationId": "createWorkspace",
        "tags": [
          "Workspaces"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkspaceRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          }
        }
      }
    },
    "/orgs/{org_id}/workspaces/{ws_id}": {
      "get": {
        "summary": "Get workspace",
        "operationId": "getWorkspace",
        "tags": [
          "Workspaces"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Soft-delete workspace",
        "operationId": "deleteWorkspace",
        "tags": [
          "Workspaces"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          }
        }
      }
    },
    "/orgs/{org_id}/workspaces/{ws_id}/members": {
      "post": {
        "summary": "Add workspace member",
        "operationId": "addWorkspaceMember",
        "tags": [
          "Workspaces"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "user_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "admin",
                      "member",
                      "viewer"
                    ]
                  }
                },
                "required": [
                  "user_id",
                  "role"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Added"
          }
        }
      }
    },
    "/orgs/{org_id}/workspaces/{ws_id}/knowledge-bases": {
      "get": {
        "summary": "List knowledge bases",
        "operationId": "listKnowledgeBases",
        "tags": [
          "KnowledgeBases"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/KnowledgeBase"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create knowledge base",
        "operationId": "createKnowledgeBase",
        "tags": [
          "KnowledgeBases"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "settings": {
                    "type": "object"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBase"
                }
              }
            }
          }
        }
      }
    },
    "/orgs/{org_id}/workspaces/{ws_id}/knowledge-bases/{kb_id}/hybrid-search": {
      "post": {
        "summary": "Hybrid (vector + BM25) search within a knowledge base",
        "description": "Fuses pgvector cosine similarity with PostgreSQL tsvector BM25\nranking via Reciprocal Rank Fusion (RRF). The caller may supply a\npre-computed query embedding for the vector leg; if omitted, the\nresponse degrades cleanly to BM25-only ranking. `top_k` is clamped\nserver-side to `retrieval.max_limit`.\n",
        "operationId": "hybridSearchKnowledgeBase",
        "tags": [
          "Search"
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "ws_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "kb_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HybridSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HybridSearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — missing/empty query or malformed body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — caller is not a workspace member",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "summary": "Get current user profile",
        "operationId": "getCurrentUser",
        "tags": [
          "Users"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    },
    "/marketplace": {
      "get": {
        "summary": "List Public KBs on the Marketplace",
        "description": "Paginated cross-tenant listing of `visibility='public'` KBs.\nBacked by the `marketplace_list_public_kbs()` SECURITY DEFINER\nfunction (ADR-0005). Authenticated Users only; anonymous browsing\nis explicitly deferred.\n",
        "operationId": "listMarketplace",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Free-text search across `name` and `description`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "most_imported",
                "recently_updated",
                "alphabetic"
              ],
              "default": "recently_updated"
            }
          },
          {
            "name": "license",
            "in": "query",
            "description": "Repeatable filter on SPDX id; ORed together.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketplaceListing"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/marketplace/{org_slug}/{kb_slug}": {
      "get": {
        "summary": "Get a Public KB by org_slug and kb_slug",
        "description": "Returns the public-facing KB detail row. The 410 Gone response is\nused (not 404) when the `(org_id, kb_slug)` pair is present in\n`kb_slug_holds` with `held_until > now()` — i.e. the KB was\nunpublished within the 90-day slug-hold window (ADR-0007).\n",
        "operationId": "getMarketplaceKb",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "org_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kb_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBase"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown org_slug or kb_slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "410": {
            "description": "Gone — the slug pair is in `kb_slug_holds`. Distinguishes\n\"previously published, now unpublished\" from \"never existed\".\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/marketplace/{org_slug}/{kb_slug}/preview": {
      "get": {
        "summary": "Preview a Public KB (≤3 sample Chunks)",
        "description": "Returns up to three sample Chunks from the target Public KB. The\nonly sanctioned cross-tenant read of Chunk rows in the system;\nbacked by the `marketplace_preview_kb()` SECURITY DEFINER function\nwhich raises `insufficient_privilege` if `visibility != 'public'`\n(ADR-0007).\n",
        "operationId": "previewMarketplaceKb",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "org_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kb_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketplacePreview"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Target KB is not `visibility='public'`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown org_slug or kb_slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "410": {
            "description": "Slug is in `kb_slug_holds`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/marketplace/import/{public_kb_id}": {
      "post": {
        "summary": "Import a Public KB as a content-grade fork",
        "description": "Creates a new Imported KB row in the chosen Workspace. Content is\ncopied via the `KB → PublishedKBProjection` projector (ADR-0002);\noriginal file blobs are not crossed. `source_public_kb_id` and\n`imported_from_revision_at` are set on the new row (ADR-0001).\nFree Plan Orgs have `visibility` forced to `public` (ADR-0004).\n",
        "operationId": "importMarketplaceKb",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "public_kb_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Imported",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a member of the destination workspace, or target KB is not public.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown `public_kb_id` or `workspace_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Plan-rule violation (e.g. Free Plan attempting to set `visibility='private'`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/knowledge_bases/{id}/publish": {
      "post": {
        "summary": "Publish a KB to the Marketplace",
        "description": "Flips `visibility` to `public` and sets `published_at`,\n`published_by_user_id`, and `license_spdx_id`. The license must be\none of the seven SPDX ids in the allow-list (ADR-0006); other\nvalues return 422. Slug re-use during the 90-day hold window\nreturns 409.\n",
        "operationId": "publishKnowledgeBase",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Published",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBase"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Plan or permission violation (e.g. Free Plan Org trying to set `visibility='private'`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "KB not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Slug is held in `kb_slug_holds` for this Org.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "License not in the SPDX allow-list, or KB has no documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/knowledge_bases/{id}/unpublish": {
      "post": {
        "summary": "Unpublish a KB from the Marketplace",
        "description": "Flips `visibility` back to `private`. The `(org_id, kb_slug)` pair\nis registered in `kb_slug_holds` with `held_until = now() + 90d`;\nthe Marketplace URL begins returning 410 (ADR-0007). Already-\nImported forks are unaffected.\n",
        "operationId": "unpublishKnowledgeBase",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unpublished",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBase"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks `kb:publish`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "KB not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/knowledge_bases/{id}/re-import": {
      "post": {
        "summary": "Re-import the source revision into an Imported KB",
        "description": "Re-runs the projection apply against the current state of the\nsource Public KB, bumping `imported_from_revision_at`. Destructive\nfor any local edits; the `confirm: true` flag is required to\nproceed (ADR-0001). Only callable when `source_public_kb_id IS\nNOT NULL`.\n",
        "operationId": "reImportKnowledgeBase",
        "tags": [
          "Marketplace"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Re-imported",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBase"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks `kb:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "KB not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "KB is not an import (`source_public_kb_id IS NULL`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "410": {
            "description": "Source Public KB was unpublished.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "`confirm` flag missing or not `true`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/marketplace/reports": {
      "post": {
        "summary": "Submit a Marketplace moderation report",
        "description": "Logged-in Users only. Per-User rate-limited; bursts return 429.\n",
        "operationId": "submitMarketplaceReport",
        "tags": [
          "Marketplace"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Report queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketplaceReport"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Reported KB not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Per-User rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/admin/marketplace/reports": {
      "get": {
        "summary": "List Marketplace reports (admin)",
        "description": "Admin-only review queue.",
        "operationId": "listMarketplaceReportsAdmin",
        "tags": [
          "Marketplace Admin"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "reviewing",
                "resolved",
                "dismissed"
              ],
              "default": "open"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MarketplaceReport"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/admin/marketplace/reports/{id}/approve": {
      "post": {
        "summary": "Approve a Marketplace report (admin)",
        "description": "Marks the report `resolved`, unpublishes the target KB (entering\nthe 90-day slug-hold), and increments\n`organizations.takedown_strikes` (ADR-0006).\n",
        "operationId": "approveMarketplaceReportAdmin",
        "tags": [
          "Marketplace Admin"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketplaceReport"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Report not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/admin/marketplace/reports/{id}/dismiss": {
      "post": {
        "summary": "Dismiss a Marketplace report (admin)",
        "description": "Marks the report `dismissed` with no further action.",
        "operationId": "dismissMarketplaceReportAdmin",
        "tags": [
          "Marketplace Admin"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dismissed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketplaceReport"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Report not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/admin/marketplace/dmca": {
      "post": {
        "summary": "File a DMCA takedown notice (admin)",
        "description": "Admin-only intake for DMCA notices. Queues the notice for the\n14-day counter-notice window before the target KB is unpublished\n(ADR-0006).\n",
        "operationId": "fileMarketplaceDMCANoticeAdmin",
        "tags": [
          "Marketplace Admin"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DMCANotice"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DMCANoticeReceipt"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Target KB not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  }
}