diff --git a/api/databases/add-columns.mdx b/api/databases/add-columns.mdx new file mode 100644 index 0000000000..0d1dd27192 --- /dev/null +++ b/api/databases/add-columns.mdx @@ -0,0 +1,11 @@ +--- +title: "Add columns" +openapi: "/databases-openapi.json POST /databases/{projectId}/{databaseId}/col" +keywords: ["databases", "columns", "schema"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +See [column types](/databases/columns) for how each type validates values. diff --git a/api/databases/create-database.mdx b/api/databases/create-database.mdx new file mode 100644 index 0000000000..3b80cc4760 --- /dev/null +++ b/api/databases/create-database.mdx @@ -0,0 +1,9 @@ +--- +title: "Create database" +openapi: "/databases-openapi.json POST /databases/{projectId}" +keywords: ["databases", "create"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/create-row.mdx b/api/databases/create-row.mdx new file mode 100644 index 0000000000..f660805ebd --- /dev/null +++ b/api/databases/create-row.mdx @@ -0,0 +1,9 @@ +--- +title: "Create row" +openapi: "/databases-openapi.json POST /databases/{projectId}/{databaseId}/row" +keywords: ["databases", "rows", "create"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/delete-column.mdx b/api/databases/delete-column.mdx new file mode 100644 index 0000000000..a869a6e764 --- /dev/null +++ b/api/databases/delete-column.mdx @@ -0,0 +1,13 @@ +--- +title: "Delete column" +openapi: "/databases-openapi.json DELETE /databases/{projectId}/{databaseId}/col/{columnId}" +keywords: ["databases", "columns"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + + + Deleting a column removes its value from every row. There is no undo. + diff --git a/api/databases/delete-database.mdx b/api/databases/delete-database.mdx new file mode 100644 index 0000000000..3b1a742f9e --- /dev/null +++ b/api/databases/delete-database.mdx @@ -0,0 +1,13 @@ +--- +title: "Delete database" +openapi: "/databases-openapi.json DELETE /databases/{projectId}/{databaseId}" +keywords: ["databases", "delete"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + + + This deletes every row in the database. There is no undo. + diff --git a/api/databases/delete-row.mdx b/api/databases/delete-row.mdx new file mode 100644 index 0000000000..155aa2849d --- /dev/null +++ b/api/databases/delete-row.mdx @@ -0,0 +1,9 @@ +--- +title: "Delete row" +openapi: "/databases-openapi.json DELETE /databases/{projectId}/{databaseId}/row/{rowId}" +keywords: ["databases", "rows", "delete"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/get-changes.mdx b/api/databases/get-changes.mdx new file mode 100644 index 0000000000..f530229df4 --- /dev/null +++ b/api/databases/get-changes.mdx @@ -0,0 +1,11 @@ +--- +title: "Get changes" +openapi: "/databases-openapi.json GET /databases/{projectId}/{databaseId}/changes" +keywords: ["databases", "changes", "change log"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +For a push-based stream of the same events, see [live updates](/databases/live-updates). diff --git a/api/databases/get-database.mdx b/api/databases/get-database.mdx new file mode 100644 index 0000000000..35a70bcff6 --- /dev/null +++ b/api/databases/get-database.mdx @@ -0,0 +1,9 @@ +--- +title: "Get database" +openapi: "/databases-openapi.json GET /databases/{projectId}/{databaseId}" +keywords: ["databases", "get"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/get-row.mdx b/api/databases/get-row.mdx new file mode 100644 index 0000000000..a04a082365 --- /dev/null +++ b/api/databases/get-row.mdx @@ -0,0 +1,9 @@ +--- +title: "Get row" +openapi: "/databases-openapi.json GET /databases/{projectId}/{databaseId}/row/{rowId}" +keywords: ["databases", "rows"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/get-schema.mdx b/api/databases/get-schema.mdx new file mode 100644 index 0000000000..41dfc872cb --- /dev/null +++ b/api/databases/get-schema.mdx @@ -0,0 +1,9 @@ +--- +title: "Get schema" +openapi: "/databases-openapi.json GET /databases/{projectId}/{databaseId}/col" +keywords: ["databases", "schema", "columns"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/list-databases.mdx b/api/databases/list-databases.mdx new file mode 100644 index 0000000000..0100d7d9c2 --- /dev/null +++ b/api/databases/list-databases.mdx @@ -0,0 +1,9 @@ +--- +title: "List databases" +openapi: "/databases-openapi.json GET /databases/{projectId}" +keywords: ["databases", "list"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/list-rows.mdx b/api/databases/list-rows.mdx new file mode 100644 index 0000000000..18fd61c3af --- /dev/null +++ b/api/databases/list-rows.mdx @@ -0,0 +1,22 @@ +--- +title: "List rows" +openapi: "/databases-openapi.json GET /databases/{projectId}/{databaseId}/rows" +keywords: ["databases", "rows", "filter", "sort", "cursor"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +## Filtering + +Filter with one query parameter per column, `where[]=`. Values are coerced to the column type, so `where[col_x]=true` works on a boolean column and `where[col_x]=42` on a number column. For `multi_select` columns the filter matches rows whose array contains the value. `json` columns cannot be filtered. + +```bash +curl "https://api.mintlify.com/v1/databases/$PROJECT_ID/$DATABASE_ID/rows?where\[col_qtxj9tuf\]=published&sort=col_8f2k1a0p:desc&limit=50" \ + -H "Authorization: Bearer $MINT_API_KEY" +``` + +## Paging + +Pass `nextCursor` from one page as `cursor` on the next. Cursors are keyset based, so a row inserted or deleted between two requests is never skipped or repeated. diff --git a/api/databases/update-column.mdx b/api/databases/update-column.mdx new file mode 100644 index 0000000000..63181206bd --- /dev/null +++ b/api/databases/update-column.mdx @@ -0,0 +1,9 @@ +--- +title: "Update column" +openapi: "/databases-openapi.json PATCH /databases/{projectId}/{databaseId}/col/{columnId}" +keywords: ["databases", "columns", "rename"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + diff --git a/api/databases/update-row.mdx b/api/databases/update-row.mdx new file mode 100644 index 0000000000..d34632cd9f --- /dev/null +++ b/api/databases/update-row.mdx @@ -0,0 +1,13 @@ +--- +title: "Update row" +openapi: "/databases-openapi.json PATCH /databases/{projectId}/{databaseId}/row/{rowId}" +keywords: ["databases", "rows", "If-Match", "revision"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +## Conditional writes + +Every row carries a `rev` that increments on each update. Send `If-Match: ` with the value you last read. If someone else updated the row in between, the response is `409` with `code: "stale_revision"` and the current `rev`, and nothing is written. diff --git a/api/databases/upsert-rows.mdx b/api/databases/upsert-rows.mdx new file mode 100644 index 0000000000..1b2831661d --- /dev/null +++ b/api/databases/upsert-rows.mdx @@ -0,0 +1,13 @@ +--- +title: "Bulk upsert rows" +openapi: "/databases-openapi.json PUT /databases/{projectId}/{databaseId}/rows" +keywords: ["databases", "rows", "bulk", "upsert", "import"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + + + Choose your own row ids, for example a UUID derived from your product's primary key, so repeated pipeline runs update rows instead of duplicating them. + diff --git a/databases-openapi.json b/databases-openapi.json new file mode 100644 index 0000000000..889080b752 --- /dev/null +++ b/databases-openapi.json @@ -0,0 +1,1568 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Mintlify Databases API", + "description": "Create databases, manage their columns, and read and write rows. Databases are in early access and enabled per project.", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.mintlify.com/v1" + } + ], + "security": [ + { + "bearerAuth": [] + } + ], + "paths": { + "/databases/{projectId}": { + "get": { + "summary": "List databases", + "operationId": "listDatabases", + "description": "List the databases on a project, oldest first.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + } + ], + "responses": { + "200": { + "description": "The project's databases.", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "databases" + ], + "properties": { + "databases": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Database" + } + } + } + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "summary": "Create database", + "operationId": "createDatabase", + "description": "Create a database. The slug is derived from the name unless you pass one. It is used by the `` component to reference the database from a page.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDatabase" + } + } + } + }, + "responses": { + "201": { + "description": "The database. `status` is `ready` once storage is initialised.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Database" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "409": { + "description": "A database with this slug already exists on the project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "The name is empty or no slug can be derived from it.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}": { + "get": { + "summary": "Get database", + "operationId": "getDatabase", + "description": "Get a database. If the database is still `initializing`, this call retries initialisation.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "responses": { + "200": { + "description": "The database.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Database" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "delete": { + "summary": "Delete database", + "operationId": "deleteDatabase", + "description": "Delete a database and every row in it. There is no undo.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "responses": { + "200": { + "description": "Deleted.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "deleted": { + "type": "string", + "format": "uuid" + } + } + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/col": { + "get": { + "summary": "Get schema", + "operationId": "getSchema", + "description": "Get the database's columns and the latest change sequence.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "responses": { + "200": { + "description": "The schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Schema" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "summary": "Add columns", + "operationId": "addColumns", + "description": "Add one or more columns. A database can have at most 100 columns and 60 indexed columns. A new column cannot be `required` when the database already has rows; add it optional, backfill, then set `required`.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "columns" + ], + "properties": { + "columns": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/components/schemas/ColumnInput" + } + } + } + } + } + } + }, + "responses": { + "201": { + "description": "The full column list, including the new ids.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ColumnList" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/col/{columnId}": { + "patch": { + "summary": "Update column", + "operationId": "updateColumn", + "description": "Rename, reorder, toggle `indexed` or `required`, or change `options`. Renames never touch rows. `required` can only be turned on when every row has a value.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "$ref": "#/components/parameters/columnId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateColumn" + } + } + } + }, + "responses": { + "200": { + "description": "The updated column.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Column" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + }, + "delete": { + "summary": "Delete column", + "operationId": "deleteColumn", + "description": "Delete a column and remove its value from every row.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "$ref": "#/components/parameters/columnId" + } + ], + "responses": { + "200": { + "description": "The remaining columns.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ColumnList" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/rows": { + "get": { + "summary": "List rows", + "operationId": "listRows", + "description": "List rows with optional equality filters, a sort, and cursor pagination. Filter with `where[]=`; for `multi_select` columns the filter matches rows whose array contains the value. Cursors are stable under concurrent writes.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "name": "sort", + "in": "query", + "schema": { + "type": "string" + }, + "description": "`` or `:desc`. Defaults to newest first. `json` and `multi_select` columns cannot be sorted." + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + } + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string" + }, + "description": "The `nextCursor` from the previous page." + }, + { + "name": "where[columnId]", + "in": "query", + "schema": { + "type": "string" + }, + "description": "Equality filter. Replace `columnId` with a real column id and repeat for several columns." + } + ], + "responses": { + "200": { + "description": "A page of rows.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RowPage" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + }, + "put": { + "summary": "Bulk upsert rows", + "operationId": "upsertRows", + "description": "Create or update up to 500 rows in one atomic call. An entry whose `id` matches an existing row is merged into it; any other entry becomes a new row with that id, or a generated one. If any entry fails validation, nothing is written.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "rows" + ], + "properties": { + "rows": { + "type": "array", + "minItems": 1, + "maxItems": 500, + "items": { + "$ref": "#/components/schemas/UpsertRow" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The written rows and counts.", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "rows", + "created", + "updated" + ], + "properties": { + "rows": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Row" + } + }, + "created": { + "type": "integer" + }, + "updated": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "413": { + "description": "A row exceeds 2 MB of JSON.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/row": { + "post": { + "summary": "Create row", + "operationId": "createRow", + "description": "Create a row. Values are keyed by column id and validated against each column's type. Missing required columns and unknown column ids are rejected.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RowInput" + } + } + } + }, + "responses": { + "201": { + "description": "The row, with `rev` 1.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Row" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "413": { + "description": "The row exceeds 2 MB of JSON.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/row/{rowId}": { + "get": { + "summary": "Get row", + "operationId": "getRow", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "$ref": "#/components/parameters/rowId" + } + ], + "responses": { + "200": { + "description": "The row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Row" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "patch": { + "summary": "Update row", + "operationId": "updateRow", + "description": "Merge `columns` into the row and increment `rev`. Set a column to `null` to clear it. Send `If-Match` with the `rev` you last read to make the write conditional.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "$ref": "#/components/parameters/rowId" + }, + { + "$ref": "#/components/parameters/ifMatch" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RowInput" + } + } + } + }, + "responses": { + "200": { + "description": "The updated row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Row" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "409": { + "description": "`If-Match` did not match the current `rev`. `currentRev` is included.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaleRevisionError" + } + } + } + }, + "413": { + "description": "The row exceeds 2 MB of JSON.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "422": { + "description": "Validation failed. `fields` maps each column id or query key to a reason.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + }, + "delete": { + "summary": "Delete row", + "operationId": "deleteRow", + "description": "Delete a row. Send `If-Match` to refuse the delete if the row changed since you read it.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "$ref": "#/components/parameters/rowId" + }, + { + "$ref": "#/components/parameters/ifMatch" + } + ], + "responses": { + "200": { + "description": "Deleted.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "deleted": { + "type": "string", + "format": "uuid" + } + } + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "409": { + "description": "`If-Match` did not match the current `rev`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaleRevisionError" + } + } + } + } + } + } + }, + "/databases/{projectId}/{databaseId}/changes": { + "get": { + "summary": "Get changes", + "operationId": "getChanges", + "description": "Read the change log after a sequence number, up to 500 changes. For a live stream, see the `events` endpoint on the live updates page.", + "parameters": [ + { + "$ref": "#/components/parameters/projectId" + }, + { + "$ref": "#/components/parameters/databaseId" + }, + { + "name": "since", + "in": "query", + "schema": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "description": "Return changes with `seq` greater than this." + } + ], + "responses": { + "200": { + "description": "Changes after `since`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeBatch" + } + } + } + }, + "401": { + "description": "Authentication failed, or Databases is not enabled for this project.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Unknown project, database, column, or row.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "The Authorization header expects a Bearer token. Use an admin API key. This is a server-side secret key. Generate one on the [API keys page](https://app.mintlify.com/settings/organization/api-keys) in your dashboard." + } + }, + "parameters": { + "projectId": { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Your project ID, from the API keys page in the dashboard." + }, + "databaseId": { + "name": "databaseId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "The database `id`." + }, + "columnId": { + "name": "columnId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "pattern": "^col_[a-z0-9]{8}$" + }, + "description": "The column `id`." + }, + "rowId": { + "name": "rowId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "The row `id`." + }, + "ifMatch": { + "name": "If-Match", + "in": "header", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + }, + "description": "The `rev` you last read. The write is refused with `409` if the row has changed since." + } + }, + "schemas": { + "ColumnType": { + "type": "string", + "enum": [ + "text", + "number", + "boolean", + "date", + "select", + "multi_select", + "url", + "email", + "json" + ] + }, + "Column": { + "type": "object", + "required": [ + "id", + "name", + "type", + "position", + "indexed", + "required" + ], + "properties": { + "id": { + "type": "string", + "example": "col_ua6ithuj" + }, + "name": { + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/ColumnType" + }, + "position": { + "type": "integer" + }, + "indexed": { + "type": "boolean" + }, + "required": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Allowed values. Present for `select` and `multi_select` columns." + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "ColumnInput": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "type": { + "$ref": "#/components/schemas/ColumnType" + }, + "indexed": { + "type": "boolean", + "description": "Index for filtering and sorting. Not allowed for `multi_select` or `json`." + }, + "required": { + "type": "boolean", + "description": "Every row must have a value. Not allowed when the database already has rows." + }, + "options": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Allowed values. Required for `select` and `multi_select`." + } + } + }, + "UpdateColumn": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "indexed": { + "type": "boolean" + }, + "required": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "type": "string" + } + }, + "position": { + "type": "integer", + "minimum": 0, + "description": "New index in the column order. Other columns shift to keep positions contiguous." + } + } + }, + "ColumnList": { + "type": "object", + "required": [ + "columns" + ], + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Column" + } + } + } + }, + "Schema": { + "type": "object", + "required": [ + "id", + "name", + "columns", + "latestSeq" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Column" + } + }, + "latestSeq": { + "type": "integer", + "description": "Sequence number of the most recent change." + } + } + }, + "Database": { + "type": "object", + "required": [ + "id", + "name", + "slug", + "status", + "createdBy", + "createdAt", + "updatedAt" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string", + "example": "apps" + }, + "status": { + "type": "string", + "enum": [ + "initializing", + "ready" + ] + }, + "createdBy": { + "type": "string", + "description": "The user email or `key:` that created the database." + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "CreateDatabase": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120, + "example": "Apps" + }, + "slug": { + "type": "string", + "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$", + "description": "Derived from the name when omitted." + } + } + }, + "ColumnValues": { + "type": "object", + "additionalProperties": true, + "description": "Values keyed by column id.", + "example": { + "col_ua6ithuj": "Alpha", + "col_8f2k1a0p": 4200 + } + }, + "RowInput": { + "type": "object", + "required": [ + "columns" + ], + "properties": { + "columns": { + "$ref": "#/components/schemas/ColumnValues" + } + } + }, + "UpsertRow": { + "type": "object", + "required": [ + "columns" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Merge into this row if it exists, otherwise create it with this id." + }, + "columns": { + "$ref": "#/components/schemas/ColumnValues" + } + } + }, + "Row": { + "type": "object", + "required": [ + "id", + "rev", + "columns", + "createdAt", + "updatedAt", + "createdBy", + "updatedBy" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "rev": { + "type": "integer", + "description": "Increments on every update. Use with `If-Match`." + }, + "columns": { + "$ref": "#/components/schemas/ColumnValues" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "createdBy": { + "type": "string" + }, + "updatedBy": { + "type": "string" + } + } + }, + "RowPage": { + "type": "object", + "required": [ + "rows", + "nextCursor" + ], + "properties": { + "rows": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Row" + } + }, + "nextCursor": { + "type": "string", + "nullable": true, + "description": "Pass as `cursor` for the next page. `null` on the last page." + } + } + }, + "Change": { + "type": "object", + "required": [ + "seq", + "kind", + "actor", + "at" + ], + "properties": { + "seq": { + "type": "integer" + }, + "kind": { + "type": "string", + "enum": [ + "database.updated", + "column.added", + "column.updated", + "column.deleted", + "row.created", + "row.updated", + "row.deleted" + ] + }, + "rowId": { + "type": "string", + "nullable": true + }, + "columnId": { + "type": "string", + "nullable": true + }, + "rev": { + "type": "integer", + "nullable": true + }, + "actor": { + "type": "string" + }, + "at": { + "type": "string", + "format": "date-time" + } + } + }, + "ChangeBatch": { + "type": "object", + "required": [ + "epoch", + "changes", + "latestSeq", + "oldestSeq" + ], + "properties": { + "epoch": { + "type": "string", + "format": "uuid", + "description": "Identifies this incarnation of the log. Changes when the database is deleted and recreated." + }, + "changes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Change" + } + }, + "latestSeq": { + "type": "integer" + }, + "oldestSeq": { + "type": "integer", + "description": "Oldest retained sequence. The log keeps the most recent 10,000 changes." + } + } + }, + "Error": { + "type": "object", + "required": [ + "error", + "code" + ], + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string", + "enum": [ + "bad_request", + "unauthorized", + "not_found", + "conflict", + "stale_revision", + "too_large", + "invalid", + "limit", + "upstream" + ] + } + } + }, + "ValidationError": { + "type": "object", + "required": [ + "error", + "code" + ], + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string", + "enum": [ + "invalid", + "limit" + ] + }, + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "example": { + "col_8f2k1a0p": "expected a number", + "col_zzzzzzzz": "unknown column" + } + }, + "current": { + "type": "integer" + }, + "limit": { + "type": "integer" + } + } + }, + "StaleRevisionError": { + "type": "object", + "required": [ + "error", + "code", + "currentRev" + ], + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string", + "enum": [ + "stale_revision" + ] + }, + "currentRev": { + "type": "integer" + }, + "ifMatch": { + "type": "integer" + } + } + } + } + } +} diff --git a/databases/api.mdx b/databases/api.mdx new file mode 100644 index 0000000000..e190378f85 --- /dev/null +++ b/databases/api.mdx @@ -0,0 +1,80 @@ +--- +title: "Databases REST API" +sidebarTitle: "REST API" +description: "Create databases, manage columns, and read and write rows with the Mintlify REST API from a pipeline, a partner portal, or any server-side script." +keywords: ["databases", "REST API", "rows", "columns", "bulk upsert", "If-Match", "cursor"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +Use the Databases API to keep a database current from wherever the data lives: a release pipeline, a partner portal, a spreadsheet export. + +## Authentication + +Authenticate with your admin API key. Generate one on the [API keys page](https://app.mintlify.com/settings/organization/api-keys) in your dashboard. Admin API keys begin with `mint_` and are server-side secrets. Do not expose them in client-side code. + +Copy your project ID from the same page and use it as the `projectId` path parameter. All endpoints are under `https://api.mintlify.com/v1/databases/{projectId}`. + +Writes are attributed to the API key. Rows show `createdBy` and `updatedBy` as `key:`. + +## Endpoints + +Databases + +- [List databases](/api/databases/list-databases) +- [Create database](/api/databases/create-database) +- [Get database](/api/databases/get-database) +- [Delete database](/api/databases/delete-database) + +Columns + +- [Get schema](/api/databases/get-schema) +- [Add columns](/api/databases/add-columns) +- [Update column](/api/databases/update-column) +- [Delete column](/api/databases/delete-column) + +Rows + +- [List rows](/api/databases/list-rows): filter with `where[columnId]`, sort, and page with a cursor. +- [Bulk upsert rows](/api/databases/upsert-rows): up to 500 rows per call, atomic. +- [Create row](/api/databases/create-row) +- [Get row](/api/databases/get-row) +- [Update row](/api/databases/update-row): conditional with `If-Match`. +- [Delete row](/api/databases/delete-row) + +Changes + +- [Get changes](/api/databases/get-changes): read the change log in batches. +- [Live updates](/databases/live-updates): subscribe to the same events over server-sent events. + +## Ids, not names + +Rows are keyed by column id, such as `col_ua6ithuj`, not by column name. Read the ids once from [Get schema](/api/databases/get-schema) and keep them in your integration. Renaming a column in the dashboard then changes nothing for your code. + +## Errors + +Every error is JSON with a stable `code`. + +| Status | `code` | Meaning | +| --- | --- | --- | +| `400` | `bad_request` | Malformed JSON, a bad `If-Match`, or a missing header. | +| `401` | | Missing or invalid API key, or Databases is not enabled for the project. | +| `404` | `not_found` | Unknown database, column, or row. | +| `409` | `conflict` | Slug already in use on this project. | +| `409` | `stale_revision` | `If-Match` did not match the current `rev`. Includes `currentRev`. | +| `413` | `too_large` | Row over 2 MB of JSON. | +| `422` | `invalid` | Validation failed. `fields` maps each column id or query key to a reason. | +| `422` | `limit` | A limit would be exceeded. Includes `current` and `limit`. | + +```json +{ + "error": "some values are invalid", + "code": "invalid", + "fields": { + "col_8f2k1a0p": "expected a number", + "col_zzzzzzzz": "unknown column" + } +} +``` diff --git a/databases/columns.mdx b/databases/columns.mdx new file mode 100644 index 0000000000..84cef64eb3 --- /dev/null +++ b/databases/columns.mdx @@ -0,0 +1,50 @@ +--- +title: "Column types" +description: "The column types a Mintlify database supports, how each validates values, and what indexed and required mean." +keywords: ["databases", "columns", "column types", "schema", "indexed", "required"] +--- + +Every column has a stable id, a display name, a type, and two flags. Values are validated against the type on every write. + +## Types + +| Type | Accepts | Stored as | Filter and sort | +| --- | --- | --- | --- | +| `text` | Any string. | String. | Yes | +| `number` | A finite number, or a numeric string such as `"42"`. | Number. | Yes | +| `boolean` | `true`, `false`, or the strings `"true"` and `"false"`. | Boolean. | Yes | +| `date` | An ISO 8601 date or date-time that exists on the calendar. | ISO 8601 UTC string. | Yes | +| `select` | One of the column's `options`. | String. | Yes | +| `multi_select` | An array of the column's `options`. | Array of strings. | Filter by membership; no sort. | +| `url` | An absolute `http` or `https` URL. Other schemes are rejected. | String. | Yes | +| `email` | An email address. | String. | Yes | +| `json` | Any JSON value. | As given. | No | + +Dates are normalized to UTC. `2026-09-15` is stored as `2026-09-15T00:00:00.000Z`. A date that does not exist, such as `2026-02-30`, is rejected rather than rolled over. + +`select` and `multi_select` columns must declare `options` when created. Values outside the options are rejected with the list of allowed values. + +## Flags + +### Required + +A required column must have a non-null value on every row. Two rules keep existing rows valid: + +- You cannot add a new column as required to a database that already has rows. Add it optional, backfill, then set `required`. +- You cannot set `required` on an existing column while any row lacks a value. The error tells you how many rows are missing one. + +### Indexed + +An indexed column is faster to filter and sort on. Mark the columns you use in `where` and `sort` as indexed. A database can have up to 60 indexed columns. `multi_select` and `json` columns cannot be indexed. + +## Renaming and reordering + +Rows are keyed by column id, so renaming a column changes only the schema. Reordering with `position` renumbers the other columns so positions stay unique and contiguous. + +## Deleting a column + +Deleting a column removes its values from every row. There is no undo. + + + Deleting a column is destructive. Export the rows first if you might need the values later. + diff --git a/databases/component.mdx b/databases/component.mdx new file mode 100644 index 0000000000..221670e812 --- /dev/null +++ b/databases/component.mdx @@ -0,0 +1,86 @@ +--- +title: "Database component" +sidebarTitle: "" +description: "Render a Mintlify database as a table on any page, filter and sort it, and generate a page for every row." +keywords: ["databases", "Database component", "table", "row pages", "MDX"] +--- + + + The rendering components ship after the API and dashboard. Their shape is documented here so you can plan pages; check back for availability. + + +Use `` to render a database on a page. The component reads the schema for headers and types, and the rows for content, so a page stays current without a redeploy. + +```mdx + +``` + +## Props + + + The database slug. + + + Column names to show, in order. Defaults to every column in schema order. + + + Equality filters keyed by column name, for example `{{ status: "published" }}`. + + + `name` or `name:desc`. Defaults to newest first. + + + Rows per page, up to 200. Pagination controls appear when there are more. + + + Show a search box that filters the visible rows. + + +```mdx catalog/apps.mdx + +``` + +Columns render by type: dates in the reader's locale, URLs as links, booleans as checks, `select` values as badges. + +## A page for every row + +Put a template in the database's folder using the row page convention and every row gets its own URL. + +```mdx catalog/apps/[app].mdx +--- +title: "{{ row.app }} {{ row.version }}" +--- + +{{ row.status }} + +Downloads: {{ row.downloads }} +``` + +Values are available as `row.`. The bracketed segment in the file name chooses the column that becomes the URL slug, so this template produces `/catalog/apps/alpha`, `/catalog/apps/beta`, and so on. + +## Reading rows in snippets + +For layouts the component does not cover, read rows directly in a [snippet](/create/reusable-snippets) with the `mint.db` helper. + +```mdx snippets/top-apps.mdx +export const TopApps = async () => { + const { rows } = await mint.db("apps").find({ + where: { status: "published" }, + sort: "downloads:desc", + limit: 5, + }); + return ( +
    + {rows.map((row) =>
  • {row.app}
  • )} +
+ ); +}; +``` + +`find`, `get`, and `count` are read-only. Writes go through the [REST API](/databases/api) or the dashboard. diff --git a/databases/live-updates.mdx b/databases/live-updates.mdx new file mode 100644 index 0000000000..d2b6c4e024 --- /dev/null +++ b/databases/live-updates.mdx @@ -0,0 +1,64 @@ +--- +title: "Live updates" +description: "Subscribe to a database's change stream over server-sent events and resume where you left off after a disconnect." +keywords: ["databases", "SSE", "server-sent events", "change stream", "live updates", "realtime"] +--- + +Every write to a database appends an event to its change log. Subscribe to the log to keep a portal, a dashboard, or a cache current without polling. + +## Subscribe + +```bash +GET /v1/databases/{projectId}/{databaseId}/events +Accept: text/event-stream +``` + +```bash curl +curl -N "https://api.mintlify.com/v1/databases/$PROJECT_ID/$DATABASE_ID/events" \ + -H "Authorization: Bearer $MINT_API_KEY" +``` + +The stream opens with a `ready` event, replays anything after your position, then pushes each change as it happens. + +```text +event: ready +data: {"epoch":"6e306bde-6324-4853-9188-ad08415d8a2f","latestSeq":12} + +id: 6e306bde-6324-4853-9188-ad08415d8a2f:13 +event: change +data: {"seq":13,"kind":"row.updated","rowId":"502e5c75-…","columnId":null,"rev":3,"actor":"key:key_2f8a","at":"2026-09-16T07:01:12.108Z"} + +: heartbeat +``` + +## Events + +| `event` | When | +| --- | --- | +| `ready` | The stream is open. `data` has the current `epoch` and `latestSeq`. | +| `change` | A mutation happened. `id` is `epoch:seq`. | +| `reset` | Your position is no longer valid, usually because the database was deleted and recreated. Discard local state and refetch; the stream then replays from the start. | +| `reconnect` | The stream is closing on purpose. Reconnect with the `since` value in `data`. | +| `error` | The database is gone or you lost access. | + +`change.kind` is one of `database.updated`, `column.added`, `column.updated`, `column.deleted`, `row.created`, `row.updated`, `row.deleted`. + +## Resuming + +Streams close after five minutes. Reconnect with the id of the last event you processed, either as the `Last-Event-ID` header, which browsers' `EventSource` sends automatically, or as `?since=`. + +```bash +GET /v1/databases/{projectId}/{databaseId}/events?since=6e306bde-6324-4853-9188-ad08415d8a2f:13 +``` + +Ids carry an epoch so a stale position from before a wipe-and-recreate cannot be mistaken for a valid one. If your position does not belong to the current epoch, or is ahead of the current log, you receive `reset` followed by a full replay. Always resume with the full `epoch:seq` id: a bare sequence number has no epoch to check, so the stream treats it as unknown and replays from the start. + +The log retains the most recent 10,000 changes. A position older than that also triggers `reset`. + +## Read the log without streaming + +```bash +GET /v1/databases/{projectId}/{databaseId}/changes?since=12 +``` + +Returns `{ "epoch", "changes": [...], "latestSeq", "oldestSeq" }` with up to 500 changes after `since`. Useful for batch jobs that reconcile on a schedule. diff --git a/databases/overview.mdx b/databases/overview.mdx new file mode 100644 index 0000000000..cdd833d32f --- /dev/null +++ b/databases/overview.mdx @@ -0,0 +1,52 @@ +--- +title: "Databases" +description: "Store structured content such as app catalogs, release tables, or partner listings as typed tables that Mintlify hosts, and render it on your docs pages." +keywords: ["databases", "structured content", "tables", "rows", "columns", "catalog"] +--- + + + Databases are in early access. Access is enabled per project. Contact your Mintlify account team to turn it on. + + +Use Databases to keep structured content out of Git and in a typed table that your team, your partners, and your build pipelines can write to through one API. Each database has a schema of columns and a set of rows. Mintlify hosts the data, keeps a revision on every row, and streams changes to anything that is listening. + +Databases fit content that changes on a different cadence than your prose: an app catalog with hundreds of entries maintained by external publishers, a release table that CI updates on every tag, a partner directory that a sales team edits from the dashboard. + +## How it works + +A database belongs to one project. It has: + +- **Columns.** Each column has a name, a type, and optional flags such as `required` and `indexed`. Columns have stable ids, so renaming a column never touches a row. +- **Rows.** Each row is a JSON object keyed by column id, plus a revision number, timestamps, and the actor who created and last updated it. +- **A change log.** Every mutation appends an event you can read back or subscribe to over a live stream. + +You manage the schema and the rows in the dashboard or through the [REST API](/databases/api). You render rows on a page with the [`` component](/databases/component). + +## What you can do + + + + Create a database, add columns and rows, and render them on a page. + + + Text, number, boolean, date, select, multi-select, URL, email, and JSON. + + + Create databases, manage columns, and read and write rows from CI or a partner portal. + + + Subscribe to a change stream and react to edits as they happen. + + + +## Limits + +| Limit | Value | +| --- | --- | +| Columns per database | 100 | +| Indexed columns per database | 60 | +| Row size | 2 MB of JSON | +| Rows per bulk upsert call | 500 | +| Rows per page when listing | 200 | + +These limits apply on write, so a request that would exceed one returns an error and changes nothing. diff --git a/databases/quickstart.mdx b/databases/quickstart.mdx new file mode 100644 index 0000000000..aa620832f9 --- /dev/null +++ b/databases/quickstart.mdx @@ -0,0 +1,121 @@ +--- +title: "Databases quickstart" +sidebarTitle: "Quickstart" +description: "Create your first database, define its columns, add rows from the dashboard and the API, and render them on a docs page." +keywords: ["databases", "quickstart", "create database", "add rows"] +--- + + + Databases are in early access and must be enabled for your project. Contact your Mintlify account team to turn it on. + + +This quickstart builds a small app catalog: a `Apps` database with a name, a version, a status, and a download count, rendered as a table on a docs page. + +## Prerequisites + +- A project with Databases enabled. +- An [admin API key](https://app.mintlify.com/settings/organization/api-keys) if you want to write rows from a script. Admin API keys begin with `mint_` and are server-side secrets. + + + + In your dashboard, open **Databases** for the project and select **Create**. Give it a name such as `Apps`. + + The slug is derived from the name, `apps` here. You use the slug when you render the database on a page. + + + ```bash curl + curl -X POST https://api.mintlify.com/v1/databases/$PROJECT_ID \ + -H "Authorization: Bearer $MINT_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ "name": "Apps" }' + ``` + ```json Response + { + "id": "0b50b639-bff9-43d2-8e62-b3bd93e9a41c", + "name": "Apps", + "slug": "apps", + "status": "ready", + "createdBy": "you@example.com", + "createdAt": "2026-09-16T06:52:05.737Z", + "updatedAt": "2026-09-16T06:52:05.737Z" + } + ``` + + + + + Add the columns your rows need. Mark the ones you filter or sort on as **indexed**, and the ones every row must have as **required**. + + + ```bash curl + curl -X POST https://api.mintlify.com/v1/databases/$PROJECT_ID/$DATABASE_ID/col \ + -H "Authorization: Bearer $MINT_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "columns": [ + { "name": "app", "type": "text", "required": true, "indexed": true }, + { "name": "version", "type": "text" }, + { "name": "status", "type": "select", "options": ["draft", "published"], "indexed": true }, + { "name": "downloads", "type": "number" } + ] + }' + ``` + ```json Response + { + "columns": [ + { "id": "col_ua6ithuj", "name": "app", "type": "text", "position": 0, "indexed": true, "required": true }, + { "id": "col_nzdoc64z", "name": "version", "type": "text", "position": 1, "indexed": false, "required": false }, + { "id": "col_qtxj9tuf", "name": "status", "type": "select", "position": 2, "indexed": true, "required": false, "options": ["draft", "published"] }, + { "id": "col_8f2k1a0p", "name": "downloads", "type": "number", "position": 3, "indexed": false, "required": false } + ] + } + ``` + + + Note the column ids. Rows are keyed by id, not by name, so you can rename `downloads` to `installs` later without touching a single row. + + + + Add rows in the dashboard grid, or send them from a script. Values are keyed by column id. + + ```bash curl + curl -X POST https://api.mintlify.com/v1/databases/$PROJECT_ID/$DATABASE_ID/row \ + -H "Authorization: Bearer $MINT_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "columns": { + "col_ua6ithuj": "Alpha", + "col_nzdoc64z": "1.2.0", + "col_qtxj9tuf": "published", + "col_8f2k1a0p": 4200 + } + }' + ``` + + Loading many rows at once? Use [bulk upsert](/api/databases/upsert-rows) with up to 500 rows per call. + + + Every write is validated against the schema. A wrong type, an unknown column id, or a missing required value returns `422` with one reason per column and writes nothing. + + + + + Add the component to any MDX page. It reads the schema for headers and the rows for content. + + ```mdx catalog/apps.mdx + --- + title: "App catalog" + --- + + + ``` + + See [``](/databases/component) for column selection, filtering, and per-row pages. + + + +## Next steps + +- Read about each [column type](/databases/columns) and how values are validated. +- Wire your release pipeline to the [REST API](/databases/api). +- Keep a portal or dashboard current with [live updates](/databases/live-updates).