{
  "openapi": "3.1.0",
  "info": {
    "title": "Ceisium Search API",
    "version": "1.0.0",
    "description": "Public REST contract for Ceisium Search API discovery and project-scoped website search.",
    "contact": {
      "name": "Ceisium support",
      "email": "yuvraj@ceisium.com",
      "url": "https://ceisium.com/contact/"
    }
  },
  "servers": [
    { "url": "https://api.ceisium.com" }
  ],
  "externalDocs": {
    "description": "Ceisium Search developer resources",
    "url": "https://ceisium.com/developers/"
  },
  "tags": [
    {
      "name": "Discovery",
      "description": "Unauthenticated service discovery and liveness operations."
    },
    {
      "name": "Search",
      "description": "Project-scoped website search operations that require a Search bearer key."
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Check API process liveness",
        "description": "Returns a small liveness result for the public Ceisium Search API process. It does not expose dependency or tenant details.",
        "operationId": "getServiceHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "The API process is available.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HealthResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/capabilities": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Describe the public API surface",
        "description": "Returns stable links and endpoint metadata so a client can discover the supported public Ceisium Search API without credentials.",
        "operationId": "getApiCapabilities",
        "security": [],
        "responses": {
          "200": {
            "description": "The supported public API capabilities.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CapabilitiesResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/search": {
      "post": {
        "tags": ["Search"],
        "summary": "Search one Ceisium Search project",
        "description": "Searches the indexed pages in one project. The bearer key must belong to that project and have Search scope.",
        "operationId": "searchProjectContent",
        "security": [
          { "bearerSearchKey": [] }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "description": "Browser origin. It is required when the bearer token is a Browser/public Search key.",
            "schema": {
              "type": "string",
              "format": "uri",
              "maxLength": 2048
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The project, visitor query, result count, and optional result URL scope.",
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SearchRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked website search results.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SearchResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" },
          "422": { "$ref": "#/components/responses/InvalidRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerSearchKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Ceisium Search key",
        "description": "A project-scoped Server or Browser/public Search key created in the Ceisium Search application."
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["status"],
        "properties": {
          "status": { "type": "string", "const": "ok" },
          "maintenance": {
            "type": "boolean",
            "description": "True when a controlled migration-maintenance window is active."
          }
        }
      },
      "CapabilitiesResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["service", "version", "documentation_url", "openapi_url", "endpoints"],
        "properties": {
          "service": { "type": "string", "const": "Ceisium Search API" },
          "version": { "type": "string", "const": "v1" },
          "documentation_url": {
            "type": "string",
            "format": "uri",
            "const": "https://ceisium.com/developers/"
          },
          "openapi_url": {
            "type": "string",
            "format": "uri",
            "const": "https://ceisium.com/openapi.json"
          },
          "endpoints": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/EndpointCapability" }
          }
        }
      },
      "EndpointCapability": {
        "type": "object",
        "additionalProperties": false,
        "required": ["method", "path", "authentication"],
        "properties": {
          "method": { "type": "string", "enum": ["GET", "POST"] },
          "path": { "type": "string", "enum": ["/healthz", "/v1/search"] },
          "authentication": {
            "type": "string",
            "enum": ["none", "bearer_search_key"]
          }
        }
      },
      "SearchRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["project_id", "query"],
        "properties": {
          "project_id": {
            "type": "string",
            "minLength": 1,
            "description": "The Ceisium Search project to search."
          },
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096,
            "description": "The visitor's natural-language or keyword search query."
          },
          "top_k": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 10,
            "description": "Requested result count. The key's configured maximum can reduce the effective count."
          },
          "path_prefix": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "Optional absolute URL prefix that limits returned result URLs."
          }
        },
        "examples": [
          {
            "project_id": "prj_example",
            "query": "OpenTelemetry Python instrumentation",
            "top_k": 5,
            "path_prefix": "https://docs.example.com/"
          }
        ]
      },
      "SearchResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["results"],
        "properties": {
          "results": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SearchResult" }
          },
          "latency_ms": {
            "type": "number",
            "minimum": 0,
            "description": "Server-side search latency in milliseconds."
          }
        }
      },
      "SearchResult": {
        "type": "object",
        "additionalProperties": false,
        "required": ["url", "title", "snippet", "score"],
        "properties": {
          "url": { "type": "string", "format": "uri" },
          "title": { "type": "string" },
          "snippet": { "type": "string" },
          "score": {
            "type": "number",
            "description": "Internal ranking signal. Do not show it as visitor-facing relevance copy."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["detail"],
        "properties": {
          "detail": { "type": "string" },
          "code": { "type": "string" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The bearer Search key is missing or invalid.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "PaymentRequired": {
        "description": "Billing is inactive, usage is stale, or the monthly allowance is exhausted.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Forbidden": {
        "description": "The key cannot use this project, browser origin, or result path.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "NotFound": {
        "description": "The requested project was not found.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "PayloadTooLarge": {
        "description": "The request body exceeds the supported size.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "InvalidRequest": {
        "description": "The JSON body or one of its typed fields is invalid.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "RateLimited": {
        "description": "A per-IP or total-key rate limit was reached.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "InternalError": {
        "description": "The search service could not complete the request.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Unavailable": {
        "description": "The service is temporarily unavailable during controlled maintenance.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      }
    }
  }
}
