For AI agents: markdown of this page — /docs-content-en/infra/database/schema.md documentation index — /llms.txt
Get the database schema
GET /v1/infra/servers/:id/db/schema
Returns the tables and views of the application's SQLite database with columns, indexes, primary keys and a flag showing whether the table's rows can be edited through the API. Use the schema to choose a table for reading rows and to check whether it allows edits.
Database access conditions and request limits — When the database is available and Limits.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
Parameterid (path) |
Typestring (UUID) | Requiredyes | Default— | DescriptionID of an application with kind equal to GALAXY_APP. List: GET /v1/infra/servers |
Parameterfile (query) |
Typestring | Requiredno | Defaultdata.defaultFile from GET /db |
DescriptionDatabase file path relative to /data, up to 1024 bytes in UTF-8. File list — data.files[].file in GET /db. An absolute path, . and .. segments and symbolic links are not accepted |
Other query string parameters return 400 VALIDATION_ERROR.
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/infra/servers/APP_ID/db/schema" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/infra/servers/APP_ID/db/schema" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${appId}/db/schema`,
{ headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const { success, data, error } = await res.json()
if (!success) throw new Error(error.code)
for (const t of data.tables) {
console.log(t.name, t.type, t.editability.editable ? 'editable' : t.editability.reason)
}
JavaScript — OAuth application
const res = await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${appId}/db/schema`,
{
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
}
)
const { success, data, error } = await res.json()
if (!success) throw new Error(error.code)
console.log(data.tables.map(t => t.name))
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | Descriptiontrue on success |
Fielddata.file |
Typestring | DescriptionPath of the file read, relative to /data |
Fielddata.tables |
Typearray | DescriptionTables and views, in alphabetical order. SQLite internal tables with names starting with sqlite_ are excluded |
Fielddata.tables[].name |
Typestring | DescriptionTable or view name. Pass it in :table when reading rows |
Fielddata.tables[].type |
Typestring | Descriptiontable — a table, view — a view |
Fielddata.tables[].columns |
Typearray | DescriptionColumns in declaration order, including hidden and generated ones |
Fielddata.tables[].columns[].name |
Typestring | DescriptionColumn name |
Fielddata.tables[].columns[].type |
Typestring | DescriptionColumn type as declared in the schema. An empty string if no type is declared |
Fielddata.tables[].columns[].notNull |
Typeboolean | DescriptionWhether a NOT NULL constraint is declared |
Fielddata.tables[].columns[].defaultValue |
Typestring | null | DescriptionDefault value expression as text, for example CURRENT_TIMESTAMP or 1. null if there is no default value |
Fielddata.tables[].columns[].primaryKeyPosition |
Typeinteger | DescriptionPosition of the column in the primary key, starting at 1. 0 — the column is not part of the key |
Fielddata.tables[].columns[].hidden |
Typeinteger | Description0 — a regular column, 1 — a hidden column of a virtual table, 2 — a VIRTUAL generated column, 3 — a STORED generated column |
Fielddata.tables[].indexes |
Typearray | DescriptionTable indexes |
Fielddata.tables[].indexes[].name |
Typestring | DescriptionIndex name |
Fielddata.tables[].indexes[].unique |
Typeboolean | DescriptionWhether the index is unique |
Fielddata.tables[].indexes[].origin |
Typestring | DescriptionIndex origin: c — created by CREATE INDEX, u — by a UNIQUE constraint, pk — by the primary key |
Fielddata.tables[].indexes[].partial |
Typeboolean | DescriptionWhether the index is partial, that is, has a WHERE condition |
Fielddata.tables[].indexes[].columns |
Typearray | DescriptionIndex columns in order. null in place of an expression if the index is built on an expression |
Fielddata.tables[].primaryKey |
Typearray | DescriptionPrimary key columns in order. An empty array if no key is declared |
Fielddata.tables[].editability.editable |
Typeboolean | DescriptionWhether rows can be added, updated and deleted through the API |
Fielddata.tables[].editability.keyKind |
Typestring | null | DescriptionHow a row is addressed: pk — by the primary key, rowid — by the SQLite built-in row number. null if editing is unavailable |
Fielddata.tables[].editability.keyColumns |
Typearray | DescriptionColumns the row key is built from. For rowid — a single rowid, _rowid_ or oid column. An empty array if editing is unavailable |
Fielddata.tables[].editability.reason |
Typestring | null | DescriptionWhy editing is unavailable: view — a view, virtual_table — a virtual table, no_stable_key — there is no primary key and the built-in row number is unavailable: the table is declared WITHOUT ROWID or the names rowid, _rowid_ and oid are taken by columns. null if editing is available |
Fielddata.tables[].rowCountEstimate |
Typeinteger | null | DescriptionRow count estimate from SQLite statistics. null if there are no statistics |
Fielddata.truncated |
Typeboolean | Descriptiontrue if the database has more than 500 tables and views or the schema approaches 1 MiB. The response then contains only some of the tables |
Response example
{
"success": true,
"data": {
"file": "app.db",
"tables": [
{
"name": "active_customers",
"type": "view",
"columns": [
{ "name": "id", "type": "INTEGER", "notNull": false, "defaultValue": null, "primaryKeyPosition": 0, "hidden": 0 },
{ "name": "name", "type": "TEXT", "notNull": false, "defaultValue": null, "primaryKeyPosition": 0, "hidden": 0 }
],
"indexes": [],
"primaryKey": [],
"editability": {
"editable": false,
"keyKind": null,
"keyColumns": [],
"reason": "view"
},
"rowCountEstimate": null
},
{
"name": "customers",
"type": "table",
"columns": [
{ "name": "id", "type": "INTEGER", "notNull": false, "defaultValue": null, "primaryKeyPosition": 1, "hidden": 0 },
{ "name": "name", "type": "TEXT", "notNull": true, "defaultValue": null, "primaryKeyPosition": 0, "hidden": 0 },
{ "name": "email", "type": "TEXT", "notNull": false, "defaultValue": null, "primaryKeyPosition": 0, "hidden": 0 },
{ "name": "created_at", "type": "TEXT", "notNull": false, "defaultValue": "CURRENT_TIMESTAMP", "primaryKeyPosition": 0, "hidden": 0 }
],
"indexes": [
{ "name": "idx_customers_email", "unique": false, "origin": "c", "partial": false, "columns": ["email"] }
],
"primaryKey": ["id"],
"editability": {
"editable": true,
"keyKind": "pk",
"keyColumns": ["id"],
"reason": null
},
"rowCountEstimate": null
},
{
"name": "order_items",
"type": "table",
"columns": [
{ "name": "order_id", "type": "INTEGER", "notNull": true, "defaultValue": null, "primaryKeyPosition": 1, "hidden": 0 },
{ "name": "line", "type": "INTEGER", "notNull": true, "defaultValue": null, "primaryKeyPosition": 2, "hidden": 0 },
{ "name": "sku", "type": "TEXT", "notNull": false, "defaultValue": null, "primaryKeyPosition": 0, "hidden": 0 },
{ "name": "qty", "type": "INTEGER", "notNull": false, "defaultValue": "1", "primaryKeyPosition": 0, "hidden": 0 }
],
"indexes": [
{ "name": "sqlite_autoindex_order_items_1", "unique": true, "origin": "pk", "partial": false, "columns": ["order_id", "line"] }
],
"primaryKey": ["order_id", "line"],
"editability": {
"editable": true,
"keyKind": "pk",
"keyColumns": ["order_id", "line"],
"reason": null
},
"rowCountEstimate": null
}
],
"truncated": false
}
}
Error response example
409 — a running application has closed its database connection in WAL mode:
{
"success": false,
"error": {
"code": "APP_DB_WAL_CLOSED",
"message": "A running application must keep its database connection open for reads and copies. A sleeping application can be read and copied with the connection closed.",
"details": {
"source": "sqlite",
"hint": "A running application must keep its database connection open for reads and copies. A sleeping application can be read and copied with the connection closed."
}
}
}
Retrying does not help until the running application opens the connection again. How to keep the connection open — When the database is available.
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | CodeVALIDATION_ERROR |
DescriptionAn unknown parameter was passed, or file is empty or longer than 1024 bytes |
| HTTP400 | CodeAPP_DB_INVALID_FILE |
Descriptionfile is an absolute path, contains . or .., goes through a symbolic link or does not point to an SQLite database |
| HTTP400 | CodeAPP_DB_UNSUPPORTED_PLACEMENT |
DescriptionThe application is not hosted in Galaxy |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is missing |
| HTTP401 | CodeINVALID_API_KEY |
DescriptionThe key is not recognized |
| HTTP402 | CodeBILLING_FROZEN |
DescriptionThe galaxy host is asleep and the balance is frozen — the host cannot be woken |
| HTTP403 | CodeINFRA_SCOPE_REQUIRED |
DescriptionThe key lacks the vibe:infra scope |
| HTTP403 | CodeAPP_DB_DISABLED |
DescriptionDatabase access is not enabled for the portal |
| HTTP403 | CodeSERVER_WAKE_BLOCKED |
DescriptionThe galaxy host is asleep and waking it is blocked |
| HTTP404 | CodeNOT_FOUND |
DescriptionThe application does not exist, was deleted or is not accessible to this key |
| HTTP404 | CodeAPP_DB_NOT_FOUND |
DescriptionThere is no /data volume or database file — the application has not created a database yet |
| HTTP409 | CodeAPP_DB_WAL_CLOSED |
DescriptionThe database is in WAL mode, but the -wal and -shm files are missing: a running application has closed the connection. There is no Retry-After header |
| HTTP409 | CodeAPP_DB_BUSY |
DescriptionThe host is busy with another operation, did not connect within 10 seconds, or the database is locked by an application write. The response carries a Retry-After header |
| HTTP422 | CodeAPP_DB_CORRUPT |
DescriptionThe database integrity check failed |
| HTTP422 | CodeAPP_DB_QUERY_TIMEOUT |
DescriptionReading the schema did not finish within 5 seconds |
| HTTP422 | CodeAPP_DB_SQL_ERROR |
DescriptionA table has more than 256 columns or more than 256 indexes; error.details.reason is other |
| HTTP429 | CodeRATE_LIMITED |
DescriptionThe read request limit for the portal was exceeded — Limits. The pause is in the Retry-After header |
| HTTP503 | CodeAPP_DB_TOOL_UNAVAILABLE |
DescriptionThe host is not prepared for database reads or is temporarily unavailable. The response carries a Retry-After header. Preparation — Prepare the host |
| HTTP503 | Codeuser_self_deletion_pending |
DescriptionThe key owner is deleting their account on the portal |
Full list of common API errors — Errors.
Known specifics
- Rows are not counted.
rowCountEstimatecomes from thesqlite_stat1statistics table, which is populated when the application itself runsANALYZE. The call does not count the table's rows, so without statistics the value isnull, and the estimate lags behind the data by the time since the lastANALYZE.