{
  "openapi": "3.1.0",
  "info": {
    "title": "Infrastructure Storage API",
    "version": "1.0.0",
    "description": "Per-tenant storage: each instance is an isolated SQLite database (schema-less JSON collections with vector search and read-only SQL) plus a private file prefix in Cloudflare R2. Machines use the instance API key (`x-api-key: stk_…`); the owner uses an Infrastructure Auth JWT (`/me` routes, or data routes with `X-Tenant-Id`). Resources are returned at the root in camelCase; collections are `{items, page: {limit, offset, total, hasMore}}`; errors are `{ \"error\": { \"code\", \"message\", \"details\"? } }`. AI agents should prefer the MCP server (`/mcp/<tenantId>`, OAuth 2.1), documented separately in llms-mcp.txt.",
    "contact": {
      "name": "Infrastructure",
      "url": "https://myinfrastructure.click/contact"
    },
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "servers": [
    {
      "url": "https://storage.manager.myinfrastructure.click"
    }
  ],
  "externalDocs": {
    "description": "LLM-ready implementation guide",
    "url": "https://myinfrastructure.click/products/storage/llms.txt"
  },
  "tags": [
    {
      "name": "Service",
      "description": "Public health."
    },
    {
      "name": "OAuth discovery",
      "description": "RFC 9728 metadata used by OAuth/MCP clients."
    },
    {
      "name": "Account",
      "description": "Owner routes, authenticated by the owner's Auth JWT."
    },
    {
      "name": "Collections",
      "description": "Schema-less JSON documents with filters and vector search."
    },
    {
      "name": "Blobs",
      "description": "Files in Cloudflare R2, uploaded through presigned URLs."
    },
    {
      "name": "SQL",
      "description": "Read-only SQL over the instance collections."
    },
    {
      "name": "Instance",
      "description": "Metrics, export, key rotation and termination."
    }
  ],
  "paths": {
    "/status": {
      "get": {
        "operationId": "getStatus",
        "tags": [
          "Service"
        ],
        "summary": "Service health",
        "description": "Public health check that feeds the status page. Runs three probes (catalog database read, R2 bucket listing, write-and-read-back on the data volume) and reports the worst of them as the overall `status`. A probe slower than 400 ms is `degraded`. Never fails with an error status: a broken probe is reported as `down` inside the body.",
        "security": [],
        "responses": {
          "200": {
            "description": "Current service health.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceStatus"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getProtectedResourceMetadata",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "Protected resource metadata (base)",
        "description": "RFC 9728 protected resource metadata for the MCP resource, without an instance. Lets an OAuth client discover the authorization server. Public by design.",
        "security": [],
        "responses": {
          "200": {
            "description": "Resource metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedResourceMetadata"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource/mcp": {
      "get": {
        "operationId": "getMcpProtectedResourceMetadata",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "Protected resource metadata (MCP path)",
        "description": "Same document as the base route; exists because some clients append the resource path when building the metadata URL.",
        "security": [],
        "responses": {
          "200": {
            "description": "Resource metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedResourceMetadata"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource/mcp/{tenantId}": {
      "get": {
        "operationId": "getInstanceProtectedResourceMetadata",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "Protected resource metadata for one instance",
        "description": "RFC 9728 metadata for a single instance. Its `resource` (`https://storage.manager.myinfrastructure.click/mcp/<tenantId>`) is what a client requests as the RFC 8707 resource indicator, and becomes the access token `aud`. The tenant id is echoed without an existence check.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Resource metadata for the instance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedResourceMetadata"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "getAccount",
        "tags": [
          "Account"
        ],
        "summary": "Get or create the owner and their first instance",
        "description": "Get-or-create for the authenticated owner (the token `sub`). Returns the owner's oldest instance; if the owner has none (and none can be reconciled by e-mail), an instance is created. The plaintext `apiKey` is returned only when a key is born in this call (new instance, or an instance without a valid `stk_` key); otherwise it is `null` and only `keyPrefix` identifies the key. Accepts only an Auth JWT — the `stk_` key is not accepted on `/me` routes.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "The owner and their instance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResolution"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteAccount",
        "tags": [
          "Account"
        ],
        "summary": "Delete the account",
        "description": "Confirms the owner has no instances left. Refuses with `409 HAS_RESOURCES` (listing the remaining tenant ids in `details`) while any instance exists; delete each one first with `DELETE /me/tenants/{tenantId}`. The identity itself lives in Infrastructure Auth.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "No instances remain.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted",
                    "instances"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    },
                    "instances": {
                      "type": "integer",
                      "const": 0
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/resolve": {
      "post": {
        "operationId": "resolveAccount",
        "tags": [
          "Account"
        ],
        "summary": "Get or create the owner (legacy address)",
        "description": "Same handler and response as `GET /me`, kept so existing callers do not break. New code should use `GET /me`. No request body is read.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "The owner and their instance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResolution"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/plan": {
      "get": {
        "operationId": "getPlanNotice",
        "tags": [
          "Account"
        ],
        "summary": "Plan notice",
        "description": "The owner's plan state for instance creation, as read from Payments. Never fails: when Payments cannot be reached the state is `unknown`. `message` is only set when `state` is `none` (over the free limit).",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "Plan state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlanNotice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/tenants": {
      "get": {
        "operationId": "listTenants",
        "tags": [
          "Account"
        ],
        "summary": "List the owner's instances",
        "description": "All instances owned by the token's subject, oldest first. Not paginated: `page.limit` equals the number of items, `page.total` and `page.hasMore` are `null`. Keys are never returned in plaintext here, only `keyPrefix`.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "The instances.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createTenant",
        "tags": [
          "Account"
        ],
        "summary": "Create an instance",
        "description": "Creates a new instance (isolated SQLite database + blob prefix) for the owner and returns its plaintext `apiKey` — the only time it is ever returned. Subject to the plan's instance limit: `402 PLAN_LIMIT` (plan exhausted, upgrade) or `402 SUBSCRIPTION_REQUIRED` (no plan), with `details.resource`, `current`, `limit`, `plan`. The gate fails open if Payments is unreachable. Responds 200 (not 201).",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantCreate"
              },
              "example": {
                "name": "my-app",
                "environment": "production"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new instance, with its key in plaintext.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantWithKey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/tenants/{tenantId}": {
      "patch": {
        "operationId": "updateTenant",
        "tags": [
          "Account"
        ],
        "summary": "Rename an instance or change its environment",
        "description": "Updates `name` and/or `environment`. At least one field is required (`400 VALIDATION_ERROR` otherwise). An instance that does not exist or is not owned by the caller answers `404`.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated instance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteTenant",
        "tags": [
          "Account"
        ],
        "summary": "Delete an instance",
        "description": "Deletes the instance row, its SQLite database and all of its blobs in R2. Irreversible. An instance that does not exist or is not the caller's answers `404`.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The instance was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/tenants/{tenantId}/rotate-key": {
      "post": {
        "operationId": "rotateTenantKey",
        "tags": [
          "Account"
        ],
        "summary": "Rotate an instance's API key (owner)",
        "description": "Issues a new `stk_` key for the instance using the owner token, invalidating the previous key immediately. This is the recovery path when the plaintext key was lost (`POST /rotate-key` needs the current key). The new key is returned once.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The instance with the new key in plaintext.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantWithKey"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/me/deletion-preview": {
      "get": {
        "operationId": "getAccountDeletionPreview",
        "tags": [
          "Account"
        ],
        "summary": "Preview account deletion",
        "description": "How many instances still block `DELETE /me`, and their tenant ids.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "Remaining instances.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "instances",
                    "tenants"
                  ],
                  "properties": {
                    "instances": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "tenants": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "format": "uuid"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/blob": {
      "get": {
        "operationId": "listBlobs",
        "tags": [
          "Blobs"
        ],
        "summary": "List files",
        "description": "Lists the instance's files in R2, paginated by cursor (not offset): pass the root-level `next` value back as `cursor`. `page.offset` is always 0 and `page.total` is always `null` (counting would sweep the bucket). Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns. Storage-side failures are rethrown and currently surface as a non-JSON 500.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Files per page. Default 100, clamped to 1000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Continuation token from the previous response `next`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of files.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlobList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/blob/sign": {
      "post": {
        "operationId": "signBlobUpload",
        "tags": [
          "Blobs"
        ],
        "summary": "Get a presigned upload URL",
        "description": "Uploads are two-step: this call returns a presigned R2 URL valid for 600 seconds; the client then sends the file bytes with `PUT <uploadUrl>` directly to R2 (that request does not go through this API). The stored name is `<uuid>-<sanitized filename>` (non `[a-zA-Z0-9.-]` characters become `_`). `contentType` is required by validation but is not bound into the signature. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "filename",
                  "contentType"
                ],
                "properties": {
                  "filename": {
                    "type": "string"
                  },
                  "contentType": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "filename": "report.pdf",
                "contentType": "application/pdf"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload URL issued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "uploadUrl",
                    "publicUrl"
                  ],
                  "properties": {
                    "uploadUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Presigned R2 URL; send the bytes with HTTP PUT within 600 s."
                    },
                    "publicUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Public URL the file will have after the PUT succeeds."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/blob/{name}": {
      "delete": {
        "operationId": "deleteBlob",
        "tags": [
          "Blobs"
        ],
        "summary": "Delete a file",
        "description": "Deletes one file by its stored name (as returned in `items[].name` by `GET /blob`). A leading `<tenantId>/` is tolerated and stripped; names containing `..` or NUL are refused. `404` when the file does not exist in this instance. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "Stored file name (URL-encoded).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/collection": {
      "get": {
        "operationId": "listCollections",
        "tags": [
          "Collections"
        ],
        "summary": "List collections",
        "description": "Every collection in the instance with its document count and an estimated size (extrapolated from up to 5 sample rows). Not paginated: `page.limit` equals the number of items, `page.total` and `page.hasMore` are `null`. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "The collections.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionSummaryList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/collection/{collection}": {
      "get": {
        "operationId": "queryCollection",
        "tags": [
          "Collections"
        ],
        "summary": "Query documents",
        "description": "Paginated, filtered read of one collection, optionally as a vector nearest-neighbour search. A collection that does not exist returns an empty page (`total: 0`), not 404. JSON text stored in a field is parsed back into objects/arrays. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          },
          {
            "name": "where",
            "in": "query",
            "required": false,
            "description": "JSON-encoded filter object. Keys are field names (`^[A-Za-z_][A-Za-z0-9_]{0,63}$`; others are silently ignored). A scalar value means equality; an object value maps operators to values: `$eq`, `$neq`, `$gt`, `$gte`, `$lt`, `$lte`, `$like` (the value is always wrapped in `%…%`). All conditions are combined with AND; there is no OR.",
            "schema": {
              "type": "string"
            },
            "example": "{\"status\":\"active\",\"score\":{\"$gte\":10}}"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "JSON-encoded object mapping field names to `asc` or `desc` (anything other than `asc` sorts descending). Defaults to `created_at DESC` unless a vector search is requested.",
            "schema": {
              "type": "string"
            },
            "example": "{\"created_at\":\"asc\"}"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Default 50, clamped to 1–200; the applied value is reported in `page.limit`.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Rows to skip. Takes precedence over `page` when both are sent.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Legacy 1-based page number, used only when `offset` is absent (`offset = (page - 1) * limit`).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "vectorIndex",
            "in": "query",
            "required": false,
            "description": "Vector column name (or full index name containing `_idx`) for a nearest-neighbour search. Requires `vector`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "vector",
            "in": "query",
            "required": false,
            "description": "Query embedding as a JSON array of numbers. Used together with `vectorIndex`.",
            "schema": {
              "type": "string"
            },
            "example": "[0.1,0.2,0.3]"
          },
          {
            "name": "vectorTopK",
            "in": "query",
            "required": false,
            "description": "Nearest neighbours to consider. Default 10, clamped to 1–100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "operationId": "upsertDocument",
        "tags": [
          "Collections"
        ],
        "summary": "Insert or update a document",
        "description": "Upserts one document. The collection is created on first write and the schema is inferred: each new field becomes a column typed by its first value (number → REAL, array of numbers → F32_BLOB vector with a vector index, anything else → TEXT; objects/arrays are stored as JSON). `id` is optional (a UUID is generated); if it exists, the listed fields are updated. Responds 200 (not 201). Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Document"
              },
              "example": {
                "id": "msg_123",
                "content": "User prefers dark mode",
                "tags": [
                  "ui"
                ],
                "embedding": [
                  0.1,
                  0.2,
                  0.3
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The document was saved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "saved"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "saved": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "delete": {
        "operationId": "dropCollection",
        "tags": [
          "Collections"
        ],
        "summary": "Drop a collection",
        "description": "Drops the collection and all of its documents. Irreversible. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The collection was dropped.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted",
                    "collection"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    },
                    "collection": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/collection/{collection}/bulk": {
      "post": {
        "operationId": "upsertDocuments",
        "tags": [
          "Collections"
        ],
        "summary": "Insert or update many documents",
        "description": "Upserts an array of documents in a single atomic batch, inferring the schema from the union of their fields. An empty array returns `{modified: 0, saved: true}`. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The documents were saved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "modified",
                    "saved"
                  ],
                  "properties": {
                    "modified": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "saved": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "delete": {
        "operationId": "deleteDocuments",
        "tags": [
          "Collections"
        ],
        "summary": "Delete many documents",
        "description": "Deletes documents by id (processed in chunks of 500). An empty `ids` array returns `{deleted: 0}`. `deleted` is the number of rows actually removed. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ids"
                ],
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rows deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/collection/{collection}/search": {
      "post": {
        "operationId": "searchCollection",
        "tags": [
          "Collections"
        ],
        "summary": "Query documents (body)",
        "description": "Same query as `GET /collection/{collection}`, with the options in a JSON body (`where` and `sort` as objects, `vector` as an array) — use it for long embeddings. Unlike the GET, a missing collection is an error (`404 NOT_FOUND`). Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              },
              "example": {
                "vectorIndex": "embedding",
                "vector": [
                  0.1,
                  0.2,
                  0.3
                ],
                "vectorTopK": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A page of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/collection/{collection}/{id}": {
      "delete": {
        "operationId": "deleteDocument",
        "tags": [
          "Collections"
        ],
        "summary": "Delete a document",
        "description": "Deletes one document by id. Answers `{deleted: true}` even when no row matched. A document whose id is literally `bulk` cannot be deleted through this route (the `/bulk` route takes precedence). Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          },
          {
            "$ref": "#/components/parameters/CollectionPath"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Document id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delete executed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted",
                    "id"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    },
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/stats": {
      "get": {
        "operationId": "getStats",
        "tags": [
          "Instance"
        ],
        "summary": "Instance usage metrics",
        "description": "Database size, blob bytes, collection/document counts and number of vector indexes. Note: unlike the rest of the API, the payload is wrapped in `data`. Blob bytes count only the first listing page (up to 1000 objects). Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage metrics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/sql/raw": {
      "post": {
        "operationId": "runSql",
        "tags": [
          "SQL"
        ],
        "summary": "Run a read-only SQL query",
        "description": "Runs one read-only SQL statement over the instance collections, with optional positional `?` parameters. It is the path for JOIN, OR, GROUP BY, aggregation and subqueries that the declarative query does not cover. Results are not paginated: `page.limit` equals the row count, `page.total` and `page.hasMore` are `null`; execution cost is in `stats`.\n\nAuthorization (`authorizeReadQuery`) refuses with `400 VALIDATION_ERROR`:\n- statements that do not start with `SELECT` or `WITH`, and more than one statement;\n- any reference to `pragma_*`, `dbstat`, `sqlite_dbpage`, `sqlite_stmt`, `sqlite_master`/the schema page, vector-index `*_shadow` tables or other internal tables;\n- calls to functions outside an allowlist (text, math, date/time, aggregate, window and `json_*` functions; no `sqlite_*`/`libsql_*`/`pragma_*` or vector functions);\n- **any query whose compiled plan (EXPLAIN) contains a write opcode, including writes to temporary b-trees.** In practice this rejects otherwise valid reads such as: `ORDER BY` on a non-indexed column combined with `LIMIT` (top-N sorter), `DISTINCT` and `COUNT(DISTINCT …)`, `UNION` (but not `UNION ALL`), `IN (subquery)` and `IN (…)` lists on indexed columns such as `id`, and window functions (`OVER`). These come back as \"Apenas consultas de leitura (SELECT) são permitidas.\" Workarounds: `ORDER BY` without `LIMIT`, `GROUP BY` instead of `DISTINCT`, `UNION ALL`, `JOIN`/`EXISTS`/`OR` instead of `IN`, or the declarative `GET /collection/{collection}` (which sorts and paginates).\n\nSyntax errors are also `400` with a sanitized message.\n\nAuthenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "A single SELECT or WITH statement."
                  },
                  "params": {
                    "type": "array",
                    "items": {},
                    "description": "Positional values for `?` placeholders."
                  }
                }
              },
              "example": {
                "query": "SELECT category, count(*) AS total FROM items WHERE price > ? GROUP BY category",
                "params": [
                  100
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Query result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SqlResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/RequestValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/export": {
      "get": {
        "operationId": "exportDatabase",
        "tags": [
          "Instance"
        ],
        "summary": "Export the database",
        "description": "Downloads a consistent, compacted copy of the instance database (VACUUM INTO) as a standard SQLite file, named `infrastructure-storage-<YYYY-MM-DD>.sqlite`. Blobs are not included. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "The SQLite database file.",
            "headers": {
              "Content-Disposition": {
                "description": "attachment; filename=\"infrastructure-storage-<date>.sqlite\"",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/vnd.sqlite3": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/vnd.sqlite3"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/rotate-key": {
      "post": {
        "operationId": "rotateKey",
        "tags": [
          "Instance"
        ],
        "summary": "Rotate the instance's API key",
        "description": "Issues a new `stk_` key for the authenticated instance and invalidates the current one immediately. The new key is returned once. If the current key was lost, use `POST /me/tenants/{tenantId}/rotate-key` with the owner token instead. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "The new key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotatedKey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/terminate": {
      "delete": {
        "operationId": "terminateInstance",
        "tags": [
          "Instance"
        ],
        "summary": "Terminate the instance",
        "description": "Permanently deletes the authenticated instance: its SQLite database, all of its blobs in R2 and its catalog row (the key stops working). Irreversible. Authenticate with `x-api-key: stk_…` (the instance is derived from the key), or with `Authorization: Bearer <Auth JWT>` plus the `X-Tenant-Id` header naming an instance the token owner owns.",
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "bearerAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "The instance was terminated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "terminated"
                  ],
                  "properties": {
                    "terminated": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Instance API key (`stk_` + 64 hex characters). Grants full read/write access to its own instance only (no scopes). Accepted on instance data routes, not on `/me` routes. An unknown key answers `403 FORBIDDEN`."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "RS256 JWT issued by Infrastructure Auth (issuer `riligar-auth`, verified against https://auth.worker.myinfrastructure.click/.well-known/jwks.json), e.g. a dashboard session or the token from the e-mail code flow. On `/me` routes it identifies the owner. On instance data routes it must be combined with the `X-Tenant-Id` header naming an instance the token `sub` owns."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization code with PKCE (S256), issued by Infrastructure Auth. Use it to act on behalf of a person; scopes are listed in the authorization server metadata.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://auth.worker.myinfrastructure.click/oauth/authorize",
            "tokenUrl": "https://auth.worker.myinfrastructure.click/oauth/token",
            "refreshUrl": "https://auth.worker.myinfrastructure.click/oauth/token",
            "scopes": {
              "auth:read": "Read instance data (enforced by the MCP server only).",
              "auth:write": "Write instance data (enforced by the MCP server only)."
            }
          }
        }
      }
    },
    "parameters": {
      "TenantIdHeader": {
        "name": "X-Tenant-Id",
        "in": "header",
        "required": false,
        "description": "Instance id. Required when authenticating with a Bearer token (`400 VALIDATION_ERROR` if missing; `404 NOT_FOUND` if the token owner does not own it). Ignored when `x-api-key` is sent.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "TenantIdPath": {
        "name": "tenantId",
        "in": "path",
        "required": true,
        "description": "Instance id.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "CollectionPath": {
        "name": "collection",
        "in": "path",
        "required": true,
        "description": "Collection name: `^[A-Za-z_][A-Za-z0-9_]{0,63}$`. Delete routes refuse an invalid name with 400 VALIDATION_ERROR; query/write routes currently surface it as 500 INTERNAL_ERROR.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "UNAUTHORIZED",
                  "FORBIDDEN",
                  "WRONG_AUDIENCE",
                  "INSUFFICIENT_SCOPE",
                  "NOT_FOUND",
                  "CONFLICT",
                  "NAME_TAKEN",
                  "EXPIRED",
                  "HAS_RESOURCES",
                  "VALIDATION_ERROR",
                  "UNPROCESSABLE",
                  "RATE_LIMITED",
                  "PAYLOAD_TOO_LARGE",
                  "PLAN_LIMIT",
                  "SUBSCRIPTION_REQUIRED",
                  "INTERNAL_ERROR",
                  "SERVICE_UNAVAILABLE",
                  "UPSTREAM_ERROR"
                ],
                "description": "Stable machine-readable code."
              },
              "message": {
                "type": "string",
                "description": "Human-readable (pt-BR); may change."
              },
              "details": {
                "type": "object",
                "additionalProperties": true
              },
              "retriable": {
                "type": "boolean",
                "const": true,
                "description": "Present on RATE_LIMITED, SERVICE_UNAVAILABLE and UPSTREAM_ERROR."
              }
            }
          }
        }
      },
      "RequestValidationError": {
        "type": "object",
        "description": "Elysia's built-in schema validation error (not the `Error` envelope).",
        "properties": {
          "type": {
            "type": "string",
            "const": "validation"
          },
          "on": {
            "type": "string",
            "examples": [
              "body"
            ]
          },
          "property": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "additionalProperties": true
      },
      "Page": {
        "type": "object",
        "required": [
          "limit",
          "offset",
          "total",
          "hasMore"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "description": "Applied page size."
          },
          "offset": {
            "type": "integer"
          },
          "total": {
            "type": [
              "integer",
              "null"
            ],
            "description": "`null` when the route does not count."
          },
          "hasMore": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "`null` when unknown (not counted)."
          }
        }
      },
      "Tenant": {
        "type": "object",
        "required": [
          "id",
          "tenantId",
          "keyPrefix",
          "name",
          "environment"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Catalog row id (not the instance id)."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "externalId": {
            "type": "string",
            "description": "Owner id in Infrastructure Auth (token `sub`)."
          },
          "tenantId": {
            "type": "string",
            "format": "uuid",
            "description": "The instance id."
          },
          "keyPrefix": {
            "type": [
              "string",
              "null"
            ],
            "description": "First 12 characters of the current key, e.g. `stk_a1b2c3d4`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "environment": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-form label; defaults to `production`."
          },
          "createdAt": {
            "type": "string",
            "description": "SQLite timestamp `YYYY-MM-DD HH:MM:SS` (UTC)."
          }
        }
      },
      "TenantWithKey": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Tenant"
          },
          {
            "type": "object",
            "required": [
              "apiKey"
            ],
            "properties": {
              "apiKey": {
                "type": "string",
                "pattern": "^stk_[0-9a-f]{64}$",
                "description": "Plaintext key, returned only once."
              }
            }
          }
        ]
      },
      "TenantList": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tenant"
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          }
        }
      },
      "TenantCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "environment": {
            "type": "string",
            "default": "production"
          }
        }
      },
      "TenantUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "environment": {
            "type": "string"
          }
        }
      },
      "AccountResolution": {
        "type": "object",
        "required": [
          "tenantId",
          "user",
          "apiKey",
          "keyPrefix",
          "mode"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Catalog row id (not the instance id)."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "externalId": {
            "type": "string",
            "description": "Owner id in Infrastructure Auth (token `sub`)."
          },
          "tenantId": {
            "type": "string",
            "format": "uuid",
            "description": "The instance id."
          },
          "keyPrefix": {
            "type": [
              "string",
              "null"
            ],
            "description": "First 12 characters of the current key, e.g. `stk_a1b2c3d4`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "environment": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-form label; defaults to `production`."
          },
          "user": {
            "type": "object",
            "required": [
              "id",
              "email"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          },
          "apiKey": {
            "type": [
              "string",
              "null"
            ],
            "description": "Plaintext key only when it was created in this call; otherwise `null`."
          },
          "mode": {
            "type": "string",
            "const": "auth"
          }
        }
      },
      "PlanNotice": {
        "type": "object",
        "required": [
          "state",
          "plan",
          "limit",
          "message"
        ],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "unknown",
              "active",
              "free",
              "none"
            ]
          },
          "plan": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Instance limit; `null` when unlimited or unknown."
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Blob": {
        "type": "object",
        "required": [
          "name",
          "size",
          "uploadedAt",
          "url"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Stored name, without the tenant prefix."
          },
          "size": {
            "type": "integer",
            "description": "Bytes."
          },
          "uploadedAt": {
            "type": "string",
            "description": "Display date in en-US short form, e.g. `Oct 6` (not ISO 8601)."
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "BlobList": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Blob"
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          },
          "cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cursor used for this page."
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cursor for the next page; `null` at the end."
          }
        }
      },
      "CollectionSummary": {
        "type": "object",
        "required": [
          "name",
          "documents",
          "size",
          "updated",
          "status"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "documents": {
            "type": "integer"
          },
          "size": {
            "type": "string",
            "description": "Human-readable estimate, e.g. `1.20 KB`."
          },
          "updated": {
            "type": "string",
            "description": "Always `Recently` (placeholder)."
          },
          "status": {
            "type": "string",
            "const": "active"
          }
        }
      },
      "CollectionSummaryList": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CollectionSummary"
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          }
        }
      },
      "Document": {
        "type": "object",
        "description": "Schema-less document. `id` is optional on write; `created_at` is set by the server.",
        "properties": {
          "id": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "DocumentPage": {
        "type": "object",
        "required": [
          "items",
          "page"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Document"
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          }
        }
      },
      "SearchRequest": {
        "type": "object",
        "properties": {
          "where": {
            "type": "object",
            "additionalProperties": true,
            "description": "Same filter as the `where` query parameter, as an object."
          },
          "sort": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            }
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "vectorIndex": {
            "type": "string"
          },
          "vector": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "vectorTopK": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 10
          }
        },
        "additionalProperties": true
      },
      "SqlResult": {
        "type": "object",
        "required": [
          "items",
          "page",
          "stats"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          },
          "stats": {
            "type": "object",
            "required": [
              "durationMs",
              "changes"
            ],
            "properties": {
              "durationMs": {
                "type": "number"
              },
              "changes": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Stats": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "storage",
              "collections",
              "documents",
              "vectors"
            ],
            "properties": {
              "storage": {
                "type": "object",
                "required": [
                  "db",
                  "blobs",
                  "total"
                ],
                "properties": {
                  "db": {
                    "type": "integer",
                    "description": "Database bytes."
                  },
                  "blobs": {
                    "type": "integer",
                    "description": "Blob bytes."
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              },
              "collections": {
                "type": "integer"
              },
              "documents": {
                "type": "integer"
              },
              "vectors": {
                "type": "integer",
                "description": "Number of vector indexes."
              }
            }
          }
        }
      },
      "RotatedKey": {
        "type": "object",
        "required": [
          "id",
          "tenantId",
          "keyPrefix",
          "apiKey"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Catalog row id (not the instance id)."
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "tenantId": {
            "type": "string",
            "format": "uuid",
            "description": "The instance id."
          },
          "keyPrefix": {
            "type": "string"
          },
          "apiKey": {
            "type": "string",
            "pattern": "^stk_[0-9a-f]{64}$",
            "description": "Plaintext key, returned only once."
          }
        }
      },
      "ProtectedResourceMetadata": {
        "type": "object",
        "required": [
          "resource",
          "authorization_servers",
          "scopes_supported",
          "bearer_methods_supported"
        ],
        "properties": {
          "resource": {
            "type": "string",
            "format": "uri"
          },
          "authorization_servers": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bearer_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resource_documentation": {
            "type": "string",
            "format": "uri"
          }
        },
        "example": {
          "resource": "https://storage.manager.myinfrastructure.click/mcp",
          "authorization_servers": [
            "https://auth.worker.myinfrastructure.click"
          ],
          "scopes_supported": [
            "auth:read",
            "auth:write"
          ],
          "bearer_methods_supported": [
            "header"
          ],
          "resource_documentation": "https://myinfrastructure.click/products/storage/llms-mcp.txt"
        }
      },
      "ServiceStatus": {
        "type": "object",
        "required": [
          "service",
          "status",
          "checkedAt",
          "checks"
        ],
        "properties": {
          "service": {
            "type": "string",
            "const": "storage"
          },
          "status": {
            "type": "string",
            "enum": [
              "operational",
              "degraded",
              "down"
            ]
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "dataDir": {
            "type": "string",
            "description": "Resolved data directory path."
          },
          "engine": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shard engine snapshot (restarts, timeouts)."
          },
          "checks": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "description",
                "status",
                "latencyMs"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "operational",
                    "degraded",
                    "down"
                  ]
                },
                "latencyMs": {
                  "type": "number"
                },
                "error": {
                  "type": "string",
                  "const": "unavailable"
                }
              }
            }
          }
        },
        "additionalProperties": true,
        "description": "Also carries plan-gate telemetry counters at the root."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "VALIDATION_ERROR — invalid input (e.g. bad collection name, refused SQL, missing X-Tenant-Id with a Bearer token, token without e-mail).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "UNAUTHORIZED — missing credential, or invalid/expired token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "FORBIDDEN — invalid API key, or a read-only engine error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "NOT_FOUND — the instance/resource does not exist or is not visible to the caller.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "HAS_RESOURCES / CONFLICT.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "PLAN_LIMIT or SUBSCRIPTION_REQUIRED — instance creation blocked by the plan.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RequestValidationFailed": {
        "description": "Body failed the route's schema validation (Elysia default format, status 422).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RequestValidationError"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded (default 200 requests/minute per client). Note: this response is plain text, not the `Error` envelope.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Reset": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "text/plain": {
            "schema": {
              "type": "string"
            },
            "example": "rate-limit reached"
          }
        }
      },
      "InternalError": {
        "description": "INTERNAL_ERROR.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "SERVICE_UNAVAILABLE — the instance is busy, or the engine timed out/restarted. Retriable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
