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

Terminal
curl "https://vibecode.bitrix24.com/v1/infra/servers/APP_ID/db/schema" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

Terminal
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

javascript
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

javascript
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

JSON
{
  "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:

JSON
{
  "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. rowCountEstimate comes from the sqlite_stat1 statistics table, which is populated when the application itself runs ANALYZE. The call does not count the table's rows, so without statistics the value is null, and the estimate lags behind the data by the time since the last ANALYZE.

See also