For AI agents: markdown of this page — /docs-content-en/infra/database/rows-create.md documentation index — /llms.txt
Add a row
POST /v1/infra/servers/:id/db/tables/:table/rows
Adds one row to a table in the SQLite database of a Galaxy application. Column values are passed in the request body; no SQL is needed.
Before the write, the platform saves a protective backup of the database — see Protective backups before writes. Access conditions — When the database is available.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Parameterid (path) |
Typestring | Requiredyes | DescriptionID of an application with kind equal to GALAXY_APP. List: GET /v1/infra/servers |
Parametertable (path) |
Typestring | Requiredyes | DescriptionExact table name from data.tables[].name in the GET /db/schema response, up to 256 bytes in UTF-8. The table must have editability.editable: true: views, virtual tables and tables with neither a primary key nor an available rowid do not accept rows |
Request fields (body)
The body is strict JSON: fields not listed in the table below are rejected with 400 VALIDATION_ERROR. The body is limited to 64 KiB.
| Field | Type | Required | Description |
|---|---|---|---|
Fieldfile |
Typestring | Requiredno | DescriptionRelative path to the database file inside the application volume, up to 1024 bytes in UTF-8. Defaults to the VIBE_DB_PATH value of the application container, or app.db if it is not set. Absolute paths, parent-directory traversal and symbolic links are not allowed |
Fieldvalues |
Typeobject | Requiredyes | DescriptionValues of the new row: the key is a column name from the schema, up to 256 bytes in UTF-8, the value is the cell. Up to 256 columns. An empty object {} adds a row of default values — INSERT ... DEFAULT VALUES. Generated and hidden columns cannot be passed |
Fieldvalues.<column> |
Typenull | number | string | object | Required— | Descriptionnull, a finite number, a string up to 64 KiB in UTF-8 or an object { "type": "integer", "value": "9223372036854775807" } for an exact 64-bit integer. An integer without the object is accepted only within ±9007199254740991. Booleans, arrays, BLOBs and other objects are not accepted |
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"values": {
"name": "Customer D",
"email": "d@example.com"
}
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"values": {
"name": "Customer D",
"email": "d@example.com"
}
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
values: {
name: 'Customer D',
email: 'd@example.com',
},
}),
})
const { success, data, error } = await res.json()
if (res.status === 409 && error.code === 'APP_DB_BACKUP_NOT_READY') {
// The protective backup is being prepared — retry after Retry-After seconds
console.log('Retry in', res.headers.get('Retry-After'), 's')
} else {
console.log('Protective backup:', data.backupId)
}
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
values: {
name: 'Customer D',
email: 'd@example.com',
},
}),
})
const { success, data, error } = await res.json()
if (res.status === 409 && error.code === 'APP_DB_BACKUP_NOT_READY') {
// The protective backup is being prepared — retry after Retry-After seconds
console.log('Retry in', res.headers.get('Retry-After'), 's')
} else {
console.log('Protective backup:', data.backupId)
}
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata.file |
Typestring | DescriptionDatabase file the row was added to |
Fielddata.table |
Typestring | DescriptionTable name |
Fielddata.rowCount |
Typenumber | DescriptionNumber of rows added, always 1 |
Fielddata.durationMs |
Typenumber | DescriptionWrite execution time in the database, in milliseconds |
Fielddata.backupId |
Typestring | DescriptionID of the protective backup taken before the first row edit of the last 10 minutes. Row edits in this window share one backup, and restoring it undoes all of them. Backup list — GET /db/backups, restore — POST /db/restore |
Response example
{
"success": true,
"data": {
"file": "app.db",
"rowCount": 1,
"durationMs": 0.903,
"table": "customers",
"backupId": "cb2fcdfd-bace-4932-a276-31d737337f3d"
}
}
Error response example
409 — the protective backup is not ready yet; the row was not added. The response comes with the Retry-After: 1 header:
{
"success": false,
"error": {
"code": "APP_DB_BACKUP_NOT_READY",
"message": "Database backup is not ready",
"details": {
"backupId": "cb2fcdfd-bace-4932-a276-31d737337f3d",
"retryable": true,
"retryAfterSeconds": 1
}
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP409 | CodeAPP_DB_BACKUP_NOT_READY |
DescriptionThe protective backup is being prepared; the row was not added. error.details contains backupId, retryable: true and retryAfterSeconds; the Retry-After header carries the same seconds, from 1 to 60. Retry the same request after the pause |
| HTTP409 | CodeAPP_DB_ROW_NOT_EDITABLE |
DescriptionThe table does not accept rows: a view, a virtual table or a table without an available key. Also returned when a column from values does not exist in the table or is generated |
| HTTP409 | CodeAPP_DB_BUSY |
DescriptionA deploy, migration or restore of the application or another database write is in progress, or waking the application or host is blocked. The Retry-After header is present |
| HTTP409 | CodeAPP_DB_WAL_CLOSED |
DescriptionThe protective backup was not created: a running application has closed its database connection in WAL mode. The row was not added; there is no Retry-After header. Configure the application to keep the connection open |
| HTTP400 | CodeVALIDATION_ERROR |
DescriptionThe body failed validation: values is missing, an extra field is present, a value type or file is invalid, or the table name exceeds 256 bytes |
| HTTP400 | CodeAPP_DB_INVALID_FILE |
DescriptionThe file path does not point to a valid database file inside /data |
| HTTP400 | CodeAPP_DB_UNSUPPORTED_PLACEMENT |
DescriptionThe application is not hosted in Galaxy |
| HTTP404 | CodeAPP_DB_TABLE_NOT_FOUND |
DescriptionThe database has no :table table |
| HTTP404 | CodeAPP_DB_NOT_FOUND |
DescriptionThere is no volume or database file: the application has not created a database yet |
| HTTP404 | CodeNOT_FOUND |
DescriptionThe application was not found, was deleted or is not accessible to this key |
| HTTP413 | CodePAYLOAD_TOO_LARGE |
DescriptionThe body exceeds 64 KiB or the full input of the service process exceeds 96 KiB |
| HTTP422 | CodeAPP_DB_SQL_ERROR |
DescriptionThe database rejected the insert; the transaction was rolled back. The cause is in error.details.reason, for example constraint_failed or type_mismatch |
| HTTP422 | CodeAPP_DB_QUERY_TIMEOUT |
DescriptionThe write did not finish within 30 seconds; the transaction was rolled back |
| HTTP422 | CodeAPP_DB_CORRUPT |
DescriptionThe database file is corrupted |
| HTTP422 | CodeAPP_DB_BACKUP_TIMEOUT |
DescriptionThe protective backup did not finish within the allotted time; the row was not added |
| HTTP422 | CodeAPP_DB_BACKUP_INVALID |
DescriptionThe protective backup failed validation; the row was not added |
| HTTP503 | CodeAPP_DB_PRE_CHANGE_FAILED |
DescriptionThe protective backup was not created; the row was not added. The error is reported once — the next call starts a new backup |
| HTTP503 | CodeAPP_DB_WRITE_OUTCOME_UNKNOWN |
DescriptionThe database response was lost; the row may have been added. retryable: false — do not retry automatically |
| HTTP503 | CodeAPP_DB_TOOL_UNAVAILABLE |
DescriptionThe host is not prepared or is temporarily unavailable. The Retry-After header is present |
| HTTP402 | CodeBILLING_FROZEN |
DescriptionThe portal's billing is frozen |
| HTTP402 | CodeBILLING_INSUFFICIENT |
DescriptionThe portal balance is insufficient to create a protective backup |
| HTTP403 | CodeAPP_DB_READONLY_KEY |
DescriptionA read-only key cannot change the database |
| HTTP403 | CodeAPP_DB_DISABLED |
DescriptionDatabase access is not enabled for the portal |
| HTTP403 | CodeINFRA_SCOPE_REQUIRED |
DescriptionThe key lacks the vibe:infra scope |
| HTTP429 | CodeRATE_LIMITED |
DescriptionThe write request limit for the portal was exceeded — Limits. The pause is in the Retry-After header |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionX-Api-Key is missing |
Full list of common API errors — Errors.
Known specifics
The new row's key is not returned. The response contains neither the values nor the key of the added row. To update or delete it, read the rows through GET /db/tables/:table/rows and take the key from rowKeys.
A retry after an unknown outcome may add the row twice. There is no idempotency key. After 503 APP_DB_WRITE_OUTCOME_UNKNOWN, check the table rows first and only then send the request again.