{
  "openapi": "3.1.0",
  "info": {
    "title": "Infino API",
    "description": "The Infino hosted data-plane API: per-database table operations — create, ingest, search, and SQL.",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://api.platform.infino.ws",
      "description": "Infino Cloud"
    }
  ],
  "paths": {
    "/v1/append/{database}": {
      "post": {
        "tags": [
          "Rows"
        ],
        "summary": "Append rows",
        "description": "Append rows to a table. The body is an Arrow IPC stream, or a JSON `{\"data\": [...]}` envelope. A column the table does not have is added, typed from the rows; a value that disagrees with a column it does have is rejected.",
        "operationId": "append",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "table",
            "in": "query",
            "description": "Target table.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "The rows to append: a JSON `{\"data\": [...]}` envelope of rows keyed by column name (`application/json`), or an Arrow IPC stream of one record batch (`application/vnd.apache.arrow.stream`).",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RowsEnvelope"
              }
            },
            "application/vnd.apache.arrow.stream": {
              "schema": {
                "$ref": "#/components/schemas/ArrowIpcRows"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Rows appended. Body is an Arrow IPC row stream (application/vnd.apache.arrow.stream), or a JSON `{\"data\": [...]}` envelope."
          },
          "400": {
            "description": "Invalid request body, or rows the table refuses. A key the table has no column for adds one, typed from the values; a value whose type disagrees with a column the table already has is refused, naming the column, the type it holds and the one offered. Growing past the table's `max_fields` is refused the same way. A column a write adds is held to the same two rules a declared one is: its values may allocate at most 16384 bytes each even when null (a struct's fixed-width children add up, so `Struct{vector(4096), i32}` is 16388 and refused), and the engine must be able to write its type. Not transient: the same body fails identically. Change the value, or change the column with a `schema` patch first."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The account already stores one of its limits — rows, or vectors (one per row of a table with a vector column) — so no more can be added. Which ceiling applies depends on the account: one with no payment method on file is held to the smaller free-plan ceiling, and adding a payment method raises it. The response body names which limit was reached, the numbers, and whether a payment method would raise it. Delete rows to free space; reads and deletes are never refused for this reason. Not transient: retrying without freeing space fails identically."
          },
          "404": {
            "description": "The target table does not exist. Append never creates a table — create it first with create_table."
          },
          "409": {
            "description": "Another write to the same table was in flight, so this one was not applied. A table takes one write at a time. Transient — reissue the identical request after the `Retry-After` interval, or batch more rows per request to need fewer of them."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/bm25_search/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "BM25 full-text search",
        "description": "Ranked BM25 full-text search over a full-text-indexed column.",
        "operationId": "bm25_search",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Bm25SearchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/count/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Count matches",
        "description": "Count the rows matching a full-text query.",
        "operationId": "count",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CountRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Match count as JSON `{\"count\": <n>}`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/create_table/{database}": {
      "post": {
        "tags": [
          "Tables"
        ],
        "summary": "Create a table",
        "description": "Create a table with an Arrow schema and optional full-text and vector indexes.",
        "operationId": "create_table",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTableRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Table created."
          },
          "400": {
            "description": "Invalid request body, or a malformed table name — use non-empty [A-Za-z0-9_-], at most 128 characters, not starting with '_'."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "409": {
            "description": "Either the table name already exists — terminal, pick another name — or another catalog change was in flight, so this one was not applied. Every table in a database is created through one catalog. The second case carries a `Retry-After`; reissue the identical request after it."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/databases": {
      "get": {
        "tags": [
          "Databases"
        ],
        "summary": "List databases",
        "description": "List your account's databases and their state.",
        "operationId": "list_databases",
        "responses": {
          "200": {
            "description": "The account's databases.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListDatabasesResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "Databases"
        ],
        "summary": "Create a database",
        "description": "Register a new database for your account.",
        "operationId": "create_database",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDatabaseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Database registered."
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "The API key may not address this database; the account already owns as many databases as its plan allows (a free-plan limit — adding a payment method lifts it); or the account is not entitled to storage bindings (BYOB is an enterprise feature).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "409": {
            "description": "Database already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/databases/{name}": {
      "delete": {
        "tags": [
          "Databases"
        ],
        "summary": "Delete a database",
        "description": "Begin deleting a database. Idempotent.",
        "operationId": "delete_database",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "The database name to delete.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Database deletion begun (idempotent)."
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "412": {
            "description": "The database changed concurrently; retry the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/databases/{name}/storage/verify": {
      "post": {
        "tags": [
          "Databases"
        ],
        "summary": "Verify a storage binding",
        "description": "Prove the database's bring-your-own-bucket grant end to end; workers start only after this passes.",
        "operationId": "verify_database_storage",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "The database name.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The binding verified; workers may start."
          },
          "400": {
            "description": "No binding, or the probe failed; the message names the failing stage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "No such database.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "410": {
            "description": "The database is being purged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/delete/{database}": {
      "post": {
        "tags": [
          "Rows"
        ],
        "summary": "Delete rows",
        "description": "Delete rows matching a predicate. `table` and `predicate` are query parameters; no body.",
        "operationId": "delete",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "table",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "predicate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Row counts as JSON `{matched, n_tombstoned, n_not_found}`."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "409": {
            "description": "Another write to the same table was in flight, so this one was not applied. A table takes one write at a time. Transient — reissue the identical request after the `Retry-After` interval, or batch more rows per request to need fewer of them."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/drop_table/{database}": {
      "post": {
        "tags": [
          "Tables"
        ],
        "summary": "Drop a table",
        "description": "Drop a table from the database.",
        "operationId": "drop_table",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DropTableRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Table dropped."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "409": {
            "description": "Another catalog change was in flight, so this one was not applied. Every table in a database is dropped through one catalog. Transient — reissue the identical request after the `Retry-After` interval."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/exact_match/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Exact match",
        "description": "Exact-value match over a column.",
        "operationId": "exact_match",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExactMatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/hybrid_search/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Hybrid search",
        "description": "Hybrid BM25 and vector search, fused with reciprocal-rank fusion.",
        "operationId": "hybrid_search",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HybridSearchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/list_tables/{database}": {
      "post": {
        "tags": [
          "Tables"
        ],
        "summary": "List tables",
        "description": "List the tables in the database.",
        "operationId": "list_tables",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON array of table names."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/query_sql/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Run a SQL query",
        "description": "Run a read-only SQL query across the database's tables.",
        "operationId": "sql_query",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SqlQueryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/schema/{database}": {
      "post": {
        "tags": [
          "Tables"
        ],
        "summary": "Describe or change a table's schema",
        "description": "With `table_name` alone, return the table's columns. With `patch`, change the schema — adding, retyping, renaming, indexing or retiring a column, or creating the table when there is none — and return the schema document that results. A patch needs the `manage` capability.",
        "operationId": "schema",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SchemaRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "A describe answers the table's columns as the `[{name, type, nullable, …}]` descriptor array by default, the schema document under `encoding: \"document\"`, and an Arrow IPC schema message under `encoding: \"ipc\"`. A write answers the schema document that resulted — the patch applied, or the table created from it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SchemaResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, an unknown `encoding`, an `encoding` sent together with `patch` (a write always answers the document), a key the patch or one of its fields does not define, half a `k1`/`b` pair, a column over the width limit (values allocating more than 16384 bytes each even when null; a struct's fixed-width children add up, so `Struct{vector(4096), i32}` is 16388 and refused), a type the engine cannot write (a union, a dictionary of a view type, a map whose entries are not a key/value pair), or a patch the schema refuses: a type the frozen column disagrees with, a name a live column holds, an id no live column has, a change that needs an empty table, an index the column cannot carry. The message names the remedy."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Either the body carries `patch` and the key lacks the `manage` capability, or the account is at a storage limit: a patch creates the table when there is none, so it meets the same quota wall a row-adding write does, with the same body naming the limit. A describe is a read and is never refused for either reason."
          },
          "404": {
            "description": "The table does not exist. A describe of a name the database does not hold says so, and so does a patch that set `expected_schema_id`: a compare-and-set names a schema the caller has already read, so a missing table is a mistake rather than a lost race. A patch without the precondition creates the table instead."
          },
          "409": {
            "description": "`expected_schema_id` no longer matches: the schema moved. Describe again and resubmit."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/token_match/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Token match",
        "description": "Unranked token match over a full-text-indexed column.",
        "operationId": "token_match",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenMatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/update/{database}": {
      "post": {
        "tags": [
          "Rows"
        ],
        "summary": "Update rows",
        "description": "Replace rows matching a predicate. `table` and `predicate` are query parameters; the body carries the replacement rows (Arrow IPC or JSON), which add and are checked against the table's columns exactly as an append's are.",
        "operationId": "update",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "table",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "predicate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "The replacement rows, 1:1 with the rows the predicate matches: a JSON `{\"data\": [...]}` envelope of rows keyed by column name (`application/json`), or an Arrow IPC stream of one record batch (`application/vnd.apache.arrow.stream`).",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RowsEnvelope"
              }
            },
            "application/vnd.apache.arrow.stream": {
              "schema": {
                "$ref": "#/components/schemas/ArrowIpcRows"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Row counts as JSON `{matched, n_tombstoned, n_not_found}`. Body is the replacement rows as an Arrow IPC stream."
          },
          "400": {
            "description": "Invalid request body, or rows the table refuses. A key the table has no column for adds one, typed from the values; a value whose type disagrees with a column the table already has is refused, naming the column, the type it holds and the one offered. Growing past the table's `max_fields` is refused the same way. A column a write adds is held to the same two rules a declared one is: its values may allocate at most 16384 bytes each even when null (a struct's fixed-width children add up, so `Struct{vector(4096), i32}` is 16388 and refused), and the engine must be able to write its type. Not transient: the same body fails identically. Change the value, or change the column with a `schema` patch first."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The account already stores one of its limits — rows, or vectors (one per row of a table with a vector column) — so no more can be added. Which ceiling applies depends on the account: one with no payment method on file is held to the smaller free-plan ceiling, and adding a payment method raises it. The response body names which limit was reached, the numbers, and whether a payment method would raise it. Delete rows to free space; reads and deletes are never refused for this reason. Not transient: retrying without freeing space fails identically."
          },
          "409": {
            "description": "Another write to the same table was in flight, so this one was not applied. A table takes one write at a time. Transient — reissue the identical request after the `Retry-After` interval, or batch more rows per request to need fewer of them."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/vector_search/{database}": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Vector search",
        "description": "Vector (kNN) search over a vector column, with an optional full-text pre-filter.",
        "operationId": "vector_search",
        "parameters": [
          {
            "name": "database",
            "in": "path",
            "description": "Target database.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VectorSearchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Matching rows as an Arrow IPC stream (application/vnd.apache.arrow.stream), or JSON when the request sends `Accept: application/json`."
          },
          "400": {
            "description": "Invalid request body."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "503": {
            "description": "The database's workers are still activating, or no capacity is free to place them. Transient — retry after the `Retry-After` interval."
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ArrowIpcRows": {
        "type": "string",
        "format": "binary",
        "description": "A raw Arrow IPC stream request body: one record batch of rows, sent as\n`Content-Type: application/vnd.apache.arrow.stream`. The most efficient\ningest path — no JSON conversion; the batch's schema must match the\ntable's."
      },
      "Bm25SearchRequest": {
        "type": "object",
        "description": "`POST /v1/bm25_search/{database}`. Projection is optional (absent ⇒ the\nengine-native `_id` + `score`).",
        "required": [
          "table_name",
          "field_name",
          "query",
          "k",
          "mode"
        ],
        "properties": {
          "b": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "description": "Overrides the column's declared BM25 length normalization for this\nsearch only. Must be given together with `k1`."
          },
          "field_name": {
            "type": "string"
          },
          "k": {
            "type": "integer",
            "minimum": 0
          },
          "k1": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "description": "Overrides the column's declared BM25 term-frequency saturation for\nthis search only. Absent ⇒ score with whatever the column declared.\nMust be given together with `b`."
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "projection": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "query": {
            "type": "string"
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CountRequest": {
        "type": "object",
        "description": "`POST /v1/count/{database}`. Count of rows matching a keyword query.",
        "required": [
          "table_name",
          "field_name",
          "query",
          "mode"
        ],
        "properties": {
          "field_name": {
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "query": {
            "type": "string"
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CreateDatabaseRequest": {
        "type": "object",
        "description": "Create-database request.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The database name, unique within the account."
          },
          "storage": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/CreateDatabaseStorage",
                "description": "Bring-your-own-bucket: where this database's data should live. Omitted\nmeans platform-hosted storage, exactly as before this field existed."
              }
            ]
          }
        }
      },
      "CreateDatabaseResponse": {
        "type": "object",
        "description": "Create-database response. Empty for a platform-hosted database; a bound\none carries what the caller needs to finish the handshake.",
        "properties": {
          "storage": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/CreatedStorage",
                "description": "Present when the database was created with a storage binding."
              }
            ]
          }
        }
      },
      "CreateDatabaseStorage": {
        "oneOf": [
          {
            "type": "object",
            "description": "Amazon S3 (or an S3-compatible store via `endpoint`).",
            "required": [
              "bucket",
              "region",
              "role_arn",
              "provider"
            ],
            "properties": {
              "bucket": {
                "type": "string",
                "description": "The customer's bucket."
              },
              "endpoint": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Custom endpoint for an S3-compatible store (https only)."
              },
              "prefix": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Root inside the bucket under which everything the platform writes\nlives. Omitted roots at the bucket."
              },
              "provider": {
                "type": "string",
                "enum": [
                  "s3"
                ]
              },
              "region": {
                "type": "string",
                "description": "The bucket's region."
              },
              "requester_pays": {
                "type": "boolean",
                "description": "Whether the bucket has Requester Pays enabled."
              },
              "role_arn": {
                "type": "string",
                "description": "The customer-owned IAM role the platform will assume\n(`arn:aws:iam::<account>:role/<name>`)."
              }
            }
          },
          {
            "type": "object",
            "description": "Google Cloud Storage: the customer grants the platform's service\naccount an object role on the bucket.",
            "required": [
              "bucket",
              "region",
              "provider"
            ],
            "properties": {
              "bucket": {
                "type": "string",
                "description": "The customer's bucket."
              },
              "prefix": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Root inside the bucket. Omitted roots at the bucket."
              },
              "provider": {
                "type": "string",
                "enum": [
                  "gcs"
                ]
              },
              "region": {
                "type": "string",
                "description": "The bucket's region."
              }
            }
          },
          {
            "type": "object",
            "description": "Azure Blob Storage: the customer admin-consents the platform's Entra\napplication and grants it a data role on the storage account.",
            "required": [
              "container",
              "region",
              "tenant_id",
              "provider"
            ],
            "properties": {
              "container": {
                "type": "string",
                "description": "The customer's container."
              },
              "prefix": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Root inside the container. Omitted roots at the container."
              },
              "provider": {
                "type": "string",
                "enum": [
                  "azure"
                ]
              },
              "region": {
                "type": "string",
                "description": "The storage account's region."
              },
              "tenant_id": {
                "type": "string",
                "description": "The customer's Entra tenant id."
              }
            }
          }
        ],
        "description": "A requested storage binding, tagged by provider. Deliberately NOT the\nstored [`StorageBinding`] shape: the AWS external id is generated by the\nplatform during the create call and returned to the caller — accepting one\nfrom the request would let a caller reuse another binding's id and reopen\nthe confused-deputy hole the id exists to close."
      },
      "CreateTableRequest": {
        "type": "object",
        "description": "`POST /v1/create_table/{database}`.",
        "required": [
          "table_name"
        ],
        "properties": {
          "indexes": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Indexes"
              }
            ]
          },
          "schema": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/SchemaField"
            },
            "description": "JSON column descriptors. Exactly one of `schema` or `schema_ipc` is\nrequired. Cannot express nested types; use `schema_ipc` for those."
          },
          "schema_ipc": {
            "type": [
              "string",
              "null"
            ],
            "description": "The table's Arrow schema as a base64-encoded Arrow IPC stream carrying\nonly the schema message. Exactly one of `schema` or `schema_ipc` is\nrequired. Carries any Arrow type the engine accepts, nested included,\nshort of the two the hosted service holds every declaration to: a\ncolumn whose values allocate more than 16384 bytes each even when\nnull, and a type the engine cannot write (a union, a dictionary of a\nview type, a map whose entries are not a key/value pair)."
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CreatedStorage": {
        "type": "object",
        "description": "The binding half of a create response.",
        "required": [
          "verified"
        ],
        "properties": {
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "For AWS bindings: the external id to write into the role's trust\npolicy (`sts:ExternalId` condition). Returned exactly once, here."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the bind-time probe already passed. GCS and Azure try the\nprobe at create when the grant is already in place. AWS is always\n`false` here: the external id did not exist until this response, so\nthe customer cannot have written the trust policy yet — call\n`POST /v1/databases/{name}/storage/verify` (or the first query, which\nre-probes) once it is."
          }
        }
      },
      "DatabaseSummary": {
        "type": "object",
        "description": "One database in the account's list, with its lifecycle state.",
        "required": [
          "name",
          "state",
          "created_ms"
        ],
        "properties": {
          "created_ms": {
            "type": "integer",
            "format": "int64",
            "description": "Unix epoch milliseconds when the database was created, or `0` if unknown\n(a database registered before creation time was tracked).",
            "minimum": 0
          },
          "name": {
            "type": "string",
            "description": "The database name, unique within the account."
          },
          "state": {
            "type": "string",
            "description": "Lifecycle state: `registered` (usable), `purging` (being deleted), or\n`unreachable` (a bound database whose storage grant failed — restore\nthe grant and re-verify to restore service; the data is not lost)."
          }
        }
      },
      "DescribedColumn": {
        "type": "object",
        "description": "One column as `POST /v1/schema/{database}` describes it by default. `name`, `type` and `nullable` describe a column and a struct's own fields; a map's `key`/`value`, and a list's `item` when the element is itself nested, are types rather than fields and carry `type` and its keys alone. This is the `create_table` descriptor vocabulary widened to every type a table can hold — see `SchemaField` for which of them `create_table` accepts back. A column's stable `id`, its index and its metadata are not in this shape; ask for `encoding: \"document\"` to get those.",
        "required": [
          "type"
        ],
        "properties": {
          "dim": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Element count of a `vector` or `fixed_size_list`.",
            "minimum": 0
          },
          "fields": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/DescribedColumn"
            },
            "description": "A struct's own fields."
          },
          "item": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object"
              }
            ],
            "description": "The element's bare scalar spelling, or its own type keys."
          },
          "key": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DescribedColumn",
                "description": "A map's key type."
              }
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absent when this describes a type rather than a field — a map's\n`key`/`value`, or a nested list `item`."
          },
          "nullable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Absent alongside `name`, for the same reason."
          },
          "precision": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Total digits of a decimal.",
            "minimum": 0
          },
          "scale": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Digits after the point of a decimal; may be negative."
          },
          "type": {
            "type": "string",
            "description": "The type tag: a scalar spelling (`\"i64\"`, `\"large_utf8\"`,\n`\"timestamp_ms\"`, …), or `\"vector\"`, `\"list\"`, `\"large_list\"`,\n`\"fixed_size_list\"`, `\"struct\"`, `\"map\"`, `\"decimal\"`, `\"decimal256\"`.\nA type with no spelling at all falls back to Arrow's own display name."
          },
          "tz": {
            "type": [
              "string",
              "null"
            ],
            "description": "IANA time zone of a zoned timestamp."
          },
          "value": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DescribedColumn",
                "description": "A map's value type."
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "DropTableRequest": {
        "type": "object",
        "description": "`POST /v1/drop_table/{database}`.",
        "required": [
          "table_name"
        ],
        "properties": {
          "purge": {
            "type": "boolean",
            "description": "Also delete the table's storage subtree after the catalog commit.\nDefaults to `true` (reclaim storage); pass `false` to only unregister\nthe table from the catalog and leave the bytes in place."
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ErrorBody": {
        "type": "object",
        "description": "A JSON error body.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message."
          }
        }
      },
      "ExactMatchRequest": {
        "type": "object",
        "description": "`POST /v1/exact_match/{database}`. Unranked; projection is optional\n(absent ⇒ the engine-native `_id` + `score`).",
        "required": [
          "table_name",
          "field_name",
          "value"
        ],
        "properties": {
          "field_name": {
            "type": "string"
          },
          "projection": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "table_name": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "FtsColumn": {
        "type": "object",
        "description": "One FTS index declaration under `indexes.fts` — a column plus its\nper-column options, e.g. `{\"column\": \"body\", \"analyzer\": \"standard\"}`.\nThe fields below are the full set; every one is optional and, when\nomitted, takes the engine default — the same defaults a bare-string entry gets (see [`FtsIndex`]).\nThe object shape mirrors what the engine's hosted transport sends for a\nnon-default `FtsField`, so an option chosen through the SDK reaches the\nservice rather than being refused at the door.",
        "required": [
          "column"
        ],
        "properties": {
          "analyzer": {
            "type": [
              "string",
              "null"
            ],
            "description": "Analyzer name. `\"standard\"` — the Unicode-aware UAX #29 tokenizer —\nis the only analyzer, and what an omitted field means; any other name\nis refused."
          },
          "b": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "description": "BM25 length normalization for this column. Omitted means the engine\ndefault. Must be given together with `k1`."
          },
          "column": {
            "type": "string"
          },
          "k1": {
            "type": [
              "number",
              "null"
            ],
            "format": "float",
            "description": "BM25 term-frequency saturation for this column. Omitted means the\nengine default. Must be given together with `b`: the two interact\nthrough the length norm, so half a pair scores with a combination\nthe caller never chose."
          },
          "positions": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Record token positions, which exact phrase queries (`\"climate\npolicy\"`) need. Omitted means the engine default, `false`. Positions\nroughly double the column's full-text index, so they are a per-column\nopt-in. A column without them answers a phrase query with an error\nnaming the column, never a bag-of-words fallback. Recorded with the\ntable; it cannot be changed afterwards."
          },
          "stemmer": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stemmer applied at index and query time (`\"english\"`). Omitted means\nnone. Recorded with the table; it cannot be changed afterwards."
          },
          "stopwords": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stopword set removed at index and query time (`\"english\"`). Omitted\nmeans none. Recorded with the table; it cannot be changed afterwards."
          },
          "stored": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the raw text is kept in the table. Omitted means the engine\ndefault, `true`. `false` declares an index-only column: the text is\nsearchable (BM25, token and phrase matching) but never stored, so it\ncannot be read back — not in SQL results, not in a search projection,\nnot in predicates. `append` and `update` batches still carry the\ncolumn; it is dropped at write time."
          }
        },
        "additionalProperties": false
      },
      "FtsIndex": {
        "oneOf": [
          {
            "type": "string",
            "description": "`\"body\"` — index the column with the default options."
          },
          {
            "$ref": "#/components/schemas/FtsColumn",
            "description": "An object naming the column and any options it sets explicitly,\ne.g. `{\"column\": \"body\", \"analyzer\": \"standard\", \"k1\": 1.6,\n\"b\": 0.4}` — see [`FtsColumn`] for the full set."
          }
        ],
        "description": "One entry in `indexes.fts`. Either a bare column name — which uses the\nengine defaults — or an options object that sets them explicitly. The bare-string\nform keeps clients that send `\"fts\": [\"body\"]` working unchanged. Options\napply per column, not per table."
      },
      "HybridSearchRequest": {
        "type": "object",
        "description": "`POST /v1/hybrid_search/{database}`. BM25 + vector fused with RRF.\nProjection is optional; vector-leg serving is engine-decided.",
        "required": [
          "table_name",
          "text_field",
          "text_query",
          "mode",
          "vector_field",
          "vector_query",
          "k"
        ],
        "properties": {
          "k": {
            "type": "integer",
            "minimum": 0
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "projection": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "table_name": {
            "type": "string"
          },
          "text_field": {
            "type": "string"
          },
          "text_query": {
            "type": "string"
          },
          "vector_field": {
            "type": "string"
          },
          "vector_query": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "float"
            }
          }
        },
        "additionalProperties": false
      },
      "Indexes": {
        "type": "object",
        "description": "Index declarations for `create_table`.",
        "properties": {
          "fts": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/FtsIndex"
            },
            "description": "FTS index declarations — a bare column name (engine defaults) or an\noptions object per column (see [`FtsColumn`])."
          },
          "vector": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/VectorIndex"
            },
            "description": "Vector index declarations."
          }
        },
        "additionalProperties": false
      },
      "ListDatabasesResponse": {
        "type": "object",
        "description": "The databases in your account.",
        "required": [
          "databases"
        ],
        "properties": {
          "databases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DatabaseSummary"
            },
            "description": "The account's databases, order unspecified."
          }
        }
      },
      "Metric": {
        "type": "string",
        "description": "Vector distance metric. Accepted case-insensitively, with the aliases\n`l2` → `l2sq` and `dot` → `negdot`; serialized canonically.",
        "enum": [
          "cosine",
          "l2sq",
          "negdot"
        ]
      },
      "Mode": {
        "type": "string",
        "description": "Boolean mode for a multi-term FTS query. Accepted case-insensitively on the\nwire (`\"or\"`, `\"Or\"`, `\"OR\"`); serialized canonically lowercase.",
        "enum": [
          "or",
          "and"
        ]
      },
      "RowsEnvelope": {
        "type": "object",
        "description": "JSON row envelope for `POST /v1/append/{database}` and\n`POST /v1/update/{database}` — the `Content-Type: application/json`\nalternative to an Arrow IPC stream body. Rows are JSON objects keyed by\ncolumn name, converted server-side into one Arrow batch against the\ntable's schema.\n\nA key the table has no column for **adds** one, typed from the values in\nthe request and nullable, so earlier rows read back null for it. That is\nthe table's behaviour and not this encoding's: an Arrow batch carrying a\ncolumn the table lacks adds it on the same terms. What is specific to JSON\nis how a row is read — a nested object flattens to dot-path columns, an\narray becomes a list column, and the column's type is inferred from the\nvalues rather than stated by the caller.\n\nA value whose type disagrees with a column the table already has is a 400,\nnaming the column, the type it holds and the one offered; the write lands\nno rows. Growing past the table's `max_fields` is a 400 too. Neither is\nretryable as sent: change the value, or change the column with a `schema`\npatch first. Appending never creates a table — an unknown table name is a\n404.",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Rows as JSON objects keyed by column name."
          }
        },
        "additionalProperties": false
      },
      "SchemaColumnIndex": {
        "oneOf": [
          {
            "type": "object",
            "description": "A full-text index: what the column was tokenized under, and the BM25\nconstants it is scored with.",
            "required": [
              "analyzer",
              "positions",
              "stored",
              "k1",
              "b",
              "kind"
            ],
            "properties": {
              "analyzer": {
                "type": "string"
              },
              "b": {
                "type": "number",
                "format": "float",
                "description": "BM25 length normalization."
              },
              "k1": {
                "type": "number",
                "format": "float",
                "description": "BM25 term-frequency saturation."
              },
              "kind": {
                "type": "string",
                "enum": [
                  "fts"
                ]
              },
              "positions": {
                "type": "boolean",
                "description": "Whether term positions are stored (what a phrase query needs)."
              },
              "stemmer": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Absent when the chain does not stem."
              },
              "stopwords": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Absent when the chain removes no stopwords."
              },
              "stored": {
                "type": "boolean",
                "description": "Whether the column's text is stored in the index."
              }
            }
          },
          {
            "type": "object",
            "description": "A vector index.",
            "required": [
              "metric",
              "rot_seed",
              "rerank_codec",
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "vector"
                ]
              },
              "metric": {
                "$ref": "#/components/schemas/Metric"
              },
              "rerank_codec": {
                "type": "string",
                "description": "The on-disk rerank byte layout. A free-form name, not a closed\nset: the engine adds codecs over time."
              },
              "rot_seed": {
                "type": "string",
                "description": "The rotation seed, as a decimal **string**: it is a `u64` whose\ndefault sits above the 2^53 a JSON number carries exactly, so a\nclient that reads numbers as doubles would hand back a different\nseed than it was given."
              }
            }
          }
        ],
        "description": "The search index on a [`SchemaDocumentField`], discriminated by `kind`."
      },
      "SchemaDocument": {
        "type": "object",
        "description": "The schema document: the table's definition as the engine holds it. Returned by every schema write, and by a describe that asks for `encoding: \"document\"`. Its `schema_id` is what the next write passes as `expected_schema_id` to make itself a compare-and-set.",
        "required": [
          "schema_id",
          "last_field_id",
          "max_fields",
          "max_depth",
          "fields",
          "tombstoned"
        ],
        "properties": {
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SchemaDocumentField"
            },
            "description": "The live columns, in schema order."
          },
          "last_field_id": {
            "type": "integer",
            "format": "int32",
            "description": "The highest field id ever minted for this table, live or dropped. Ids\nare never reused, so this only grows.",
            "minimum": 0
          },
          "max_depth": {
            "type": "integer",
            "format": "int32",
            "description": "How deep a document may nest before the row mapper refuses it.",
            "minimum": 0
          },
          "max_fields": {
            "type": "integer",
            "format": "int32",
            "description": "The most live fields the table may hold.",
            "minimum": 0
          },
          "schema_id": {
            "type": "integer",
            "format": "int32",
            "description": "Bumps on every committed schema change. Pass it back as\n`expected_schema_id` to make the next write a compare-and-set.",
            "minimum": 0
          },
          "tombstoned": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "description": "Ids of columns that were dropped. Their names are free for reuse by a\nnew column, which gets a new id."
          }
        },
        "additionalProperties": false
      },
      "SchemaDocumentField": {
        "type": "object",
        "description": "One column of a schema document, and the nested fields inside it. The document spells types differently from the descriptor array a describe answers by default: a list's `item` is always a field object rather than a bare name, and a map carries Arrow's `entries` struct plus `keys_sorted` rather than a flattened `key`/`value` pair — so a client reading both encodings needs a parser for each. `id`, `index`, `converting_from` and `metadata` belong to a top-level column; a nested field carries `name`, `nullable` and its type keys alone.",
        "required": [
          "name",
          "type",
          "nullable"
        ],
        "properties": {
          "converting_from": {
            "type": [
              "object",
              "null"
            ],
            "description": "The type the column is being converted *from*, as type keys. Present\nonly while a committed type change is still being applied to the\ntable's existing files; absent once every file carries the new type."
          },
          "dim": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Element count of a `vector` or `fixed_size_list`.",
            "minimum": 0
          },
          "entries": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SchemaDocumentField",
                "description": "A map's entry field: Arrow's two-field `{key, value}` struct, as Arrow\nstores it."
              }
            ]
          },
          "fields": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/SchemaDocumentField"
            },
            "description": "A struct's own fields."
          },
          "id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Stable for the column's whole life, across renames — what a `patch`\nmatches on when it changes an existing column. Every top-level column\ncarries one; a nested field does not.",
            "minimum": 0
          },
          "index": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SchemaColumnIndex",
                "description": "The column's search index, absent when it carries none."
              }
            ]
          },
          "ipc": {
            "type": [
              "string",
              "null"
            ],
            "description": "A base64 Arrow IPC schema message carrying the one type that has no\nspelling. Present only when `type` is `\"arrow\"`."
          },
          "item": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SchemaDocumentField",
                "description": "Element field of a `list`, `large_list` or `fixed_size_list`."
              }
            ]
          },
          "item_nullable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Present, and `false`, only when a `vector`'s element is non-nullable —\nthe compact spelling's elements are nullable by default."
          },
          "keys_sorted": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether a map's keys are stored sorted."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "description": "Free-form column metadata. Absent when the column has none.\n\nCarried through unchanged but for the `infino.` namespace, which the\nservice reserves for its own marks and does not return. Only a schema\nwrite may set metadata at all: an append or update carries none, and a\nbatch that declares some has it dropped rather than refused.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": "string"
          },
          "nullable": {
            "type": "boolean"
          },
          "precision": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Total digits of a decimal.",
            "minimum": 0
          },
          "scale": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Digits after the point of a decimal; may be negative."
          },
          "type": {
            "type": "string",
            "description": "The type tag: a scalar spelling, `\"vector\"`, `\"list\"`,\n`\"large_list\"`, `\"fixed_size_list\"`, `\"struct\"`, `\"map\"`,\n`\"decimal\"`, `\"decimal256\"`, `\"fixed_size_binary\"`, or `\"arrow\"` for a\ntype with no spelling, whose Arrow form rides in `ipc`."
          },
          "tz": {
            "type": [
              "string",
              "null"
            ],
            "description": "IANA time zone of a zoned timestamp."
          },
          "width": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Byte width of a `fixed_size_binary`.",
            "minimum": 0
          }
        },
        "additionalProperties": false
      },
      "SchemaField": {
        "type": "object",
        "description": "One column in a `create_table` schema. A scalar column is `{name, type}` where `type` is one of `\"utf8\"`, `\"large_utf8\"`, `\"bool\"`, `\"i32\"`, `\"i64\"`, `\"u32\"`, `\"u64\"`, `\"f32\"`, `\"f64\"`, `\"date32\"`, `\"date64\"`, or a timezone-naive timestamp with its unit: `\"timestamp_s\"`, `\"timestamp_ms\"` (also `\"timestamp\"`), `\"timestamp_us\"`, `\"timestamp_ns\"`. A vector column is `{name, type: \"vector\", dim}`; a list column is `{name, type: \"list\", item}`. `dim` is required for `\"vector\"` and `item` for `\"list\"`. The `schema` endpoint describes every column in this same vocabulary, but what it returns is a superset of what this form accepts: a zoned timestamp carries `tz`, a decimal is `{type: \"decimal\", precision, scale}`, a struct is `{type: \"struct\", fields}`, a map is `{type: \"map\", key, value}`, and a list whose element is itself nested spells `item` as an object rather than a name. Declare any of those with `schema_ipc`, and do not hand a described column of one of those types back to `create_table` unchanged — the extra keys are rejected.",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "dim": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Fixed length, required for `type: \"vector\"`. Must be in [1, 4096].",
            "maximum": 4096,
            "minimum": 1
          },
          "item": {
            "type": [
              "string",
              "null"
            ],
            "description": "Element scalar type, required for `type: \"list\"`."
          },
          "name": {
            "type": "string",
            "description": "Column name."
          },
          "nullable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Defaults to `true` when omitted."
          },
          "type": {
            "type": "string",
            "description": "Scalar spelling (`\"i32\"`, `\"large_utf8\"`, `\"date32\"`, `\"timestamp_ms\"`, …),\nor `\"vector\"` / `\"list\"`."
          }
        },
        "additionalProperties": false
      },
      "SchemaRequest": {
        "type": "object",
        "description": "`POST /v1/schema/{database}`: one op, two shapes. With `table_name` alone\nit describes the table; with `patch` it changes the schema — or creates\nthe table when there is none — and describes the result.\n\nThe two shapes answer differently. A describe answers the\n`[{name, type, nullable, …}]` column-descriptor array, which is what it\nhas always answered; `encoding` asks for the other forms. A write answers\nthe schema document ([`SchemaDocument`]), which is what carries the\n`schema_id` the next compare-and-set needs.",
        "required": [
          "table_name"
        ],
        "properties": {
          "encoding": {
            "type": [
              "string",
              "null"
            ],
            "description": "Response encoding of a describe. Omitted (the default) returns the\n`[{name, type, nullable, …}]` column-descriptor array; `\"document\"`\nreturns the schema document ([`SchemaDocument`]), which adds each\ncolumn's stable `id`, its index and its metadata; `\"ipc\"` returns an\nArrow IPC schema message carrying the Arrow shape of the columns. Any\nother value is a 400.\n\nOnly a describe takes it: sending it together with `patch` is a 400,\nbecause a write always answers the document."
          },
          "expected_schema_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Compare-and-set against the document's `schema_id`: the write is\nrefused with 409 when the schema has moved.",
            "minimum": 0
          },
          "patch": {
            "type": [
              "object",
              "null"
            ],
            "description": "The schema write, in the document's own shape: `fields` to add or\nchange (matched by `id` when given, else by `name`; `dropped: true`\nretires one), `max_fields`, `max_depth`. Nothing is\ndropped by omission, and applying what a describe returned changes\nnothing. Requires the `manage` capability; a `patch` that is present\nand not null counts as a write, whether the body is sent as an object\nor as an array, which serde fills by position."
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "SchemaResponse": {
        "oneOf": [
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DescribedColumn"
            },
            "description": "The default answer to a describe: the table's columns in the shape\n`create_table` declares them, widened to the types it cannot declare."
          },
          {
            "$ref": "#/components/schemas/SchemaDocument",
            "description": "The answer to a schema write, and to a describe that asked for it."
          }
        ],
        "description": "What `POST /v1/schema/{database}` answers with, as JSON: the column\ndescriptors by default, the [`SchemaDocument`] when a write ran or\n`encoding: \"document\"` asked for it. (`encoding: \"ipc\"` answers an Arrow\nIPC schema message, which is not JSON and is not in this union.)\n\nUntagged: the two are told apart by their JSON shape — the descriptors are\nan array, the document an object."
      },
      "SqlQueryRequest": {
        "type": "object",
        "description": "`POST /v1/sql_query/{database}`.",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "TokenMatchRequest": {
        "type": "object",
        "description": "`POST /v1/token_match/{database}`. Unranked; projection is optional\n(absent ⇒ the engine-native `_id` + `score`).",
        "required": [
          "table_name",
          "field_name",
          "query",
          "mode"
        ],
        "properties": {
          "field_name": {
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "projection": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "query": {
            "type": "string"
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "VectorFilter": {
        "type": "object",
        "description": "Optional text pre-filter for `vector_search`: kNN ranks only among rows\nwhose FTS-indexed `field_name` matches `query`.",
        "required": [
          "field_name",
          "query",
          "mode"
        ],
        "properties": {
          "field_name": {
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "query": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "VectorIndex": {
        "type": "object",
        "description": "One vector index declaration under `indexes.vector`.",
        "required": [
          "column",
          "metric"
        ],
        "properties": {
          "column": {
            "type": "string"
          },
          "dim": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Redundant with the schema column's declared width; the server resolves\nthe dimension from the schema, so this is optional and, if given, must\nagree.",
            "minimum": 0
          },
          "metric": {
            "$ref": "#/components/schemas/Metric"
          }
        },
        "additionalProperties": false
      },
      "VectorSearchRequest": {
        "type": "object",
        "description": "`POST /v1/vector_search/{database}`. Projection is optional (absent ⇒ the\nengine-native `_id` + `score`); `filter` is an optional pushdown text\npre-filter. Probe width and rerank budget are engine-decided (drain-time\ncalibration) — there are no tuning knobs.",
        "required": [
          "table_name",
          "field_name",
          "query",
          "k"
        ],
        "properties": {
          "field_name": {
            "type": "string"
          },
          "filter": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/VectorFilter"
              }
            ]
          },
          "k": {
            "type": "integer",
            "minimum": 0
          },
          "projection": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "query": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "float"
            }
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "api_key": {
        "type": "http",
        "scheme": "bearer"
      },
      "session_cookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "infino_session"
      },
      "session_token": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Session-Token"
      }
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "tags": [
    {
      "name": "Databases",
      "description": "Create, list, and delete the databases in your account."
    },
    {
      "name": "Tables",
      "description": "Create, drop, and list tables, and describe a table's schema."
    },
    {
      "name": "Rows",
      "description": "Append, update, and delete rows."
    },
    {
      "name": "Search",
      "description": "BM25, vector, and hybrid search, token and exact match, count, and SQL."
    }
  ]
}
