{
  "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.",
        "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."
          },
          "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 a table's schema",
        "description": "Return a table's column schema.",
        "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": "JSON array of column descriptors."
          },
          "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/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).",
        "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."
          },
          "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"
          },
          "stats": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Stats",
                "description": "BM25 corpus statistics for idf scoring. Absent ⇒ the deployed\nengine's own default, whatever that is; the engine SDK's remote\ntransport always sends it explicitly."
              }
            ]
          },
          "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."
          },
          "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)."
          }
        }
      },
      "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\"` or `\"ascii_lower\"`). Omitted means the\nengine default, `standard` — the Unicode-aware UAX #29 tokenizer.\n`ascii_lower` splits on ASCII alphanumerics and drops every\nnon-ASCII token. Recorded with the table; it cannot be changed\nafterwards, so pass it explicitly to pin a column either way."
          },
          "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."
          },
          "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.",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Rows as JSON objects keyed by column name."
          }
        },
        "additionalProperties": false
      },
      "SchemaField": {
        "type": "object",
        "description": "One column in a `create_table` schema. A scalar column is `{name, type}` where `type` is a scalar spelling (`\"i32\"`, `\"large_utf8\"`, …); 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\"`.",
        "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, or `\"vector\"` / `\"list\"`."
          }
        },
        "additionalProperties": false
      },
      "SchemaRequest": {
        "type": "object",
        "description": "`POST /v1/schema/{database}`.",
        "required": [
          "table_name"
        ],
        "properties": {
          "encoding": {
            "type": [
              "string",
              "null"
            ],
            "description": "Response encoding. Omitted (the default) returns the JSON column\ndescriptors; `\"ipc\"` returns an Arrow IPC schema message, which is the\nonly form that can carry a nested column type."
          },
          "table_name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "SqlQueryRequest": {
        "type": "object",
        "description": "`POST /v1/sql_query/{database}`.",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "Stats": {
        "type": "string",
        "description": "Which BM25 corpus statistics to score term rarity (idf) with. Accepted\ncase-insensitively on the wire (`\"per_superfile\"`, `\"global\"`); serialized\ncanonically. Absent on a request ⇒ whatever the deployed engine defaults\nto, deliberately: an omitted field means \"let the engine choose\", so a\nraw REST caller and an SDK caller who both leave it out score alike, and\nthe engine can improve its default without this contract going stale. Send\nthe field explicitly to pin one mode across engine versions.",
        "enum": [
          "per_superfile",
          "global"
        ]
      },
      "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."
    }
  ]
}