Skip to main content

HTTP API

CamusDB exposes JSON endpoints for automation and application integration. Request and response properties use camelCase.

Status And Errors

Successful responses use:

{
"status": "ok"
}

Failed responses use HTTP 500 and include a CamusDB error code when available:

{
"status": "failed",
"code": "CADB0400",
"message": "error message"
}

See Error Codes for the reference list and when each code is generated.

Column Values

Rows, filters, inserts, updates, defaults, and SQL parameters use ColumnValue objects:

ColumnType is serialized as its numeric enum value: 0 null, 1 id, 2 int64, 3 string, 4 bool, and 5 float64.

{ "type": 3, "strValue": "R2-D2", "longValue": 0, "floatValue": 0, "boolValue": false }
{ "type": 2, "strValue": null, "longValue": 1977, "floatValue": 0, "boolValue": false }
{ "type": 5, "strValue": null, "longValue": 0, "floatValue": 12.5, "boolValue": false }
{ "type": 4, "strValue": null, "longValue": 0, "floatValue": 0, "boolValue": true }
{ "type": 1, "strValue": "507f1f77bcf86cd799439011", "longValue": 0, "floatValue": 0, "boolValue": false }

Health

GET /ping

Returns server status and UTC time.

{
"status": "ok",
"dateTime": "2026-05-28T18:30:00.0000000Z"
}

Databases

Databases must be created explicitly before table DDL, DML, or queries can use their name.

POST /create-db

{
"databaseName": "app",
"ifNotExists": true
}

POST /drop-db

{
"databaseName": "app"
}

The direct endpoint drops an existing database. For idempotent drops, use SQL:

{
"sql": "DROP DATABASE IF EXISTS app"
}

Database rename is also exposed through SQL:

{
"sql": "RENAME DATABASE app TO app_prod"
}

POST /close-db

{
"databaseName": "app"
}

Tables

POST /create-table

{
"databaseName": "app",
"tableName": "robots",
"ifNotExists": true,
"columns": [
{ "name": "id", "type": "id", "notNull": true, "defaultValue": null },
{ "name": "name", "type": "string", "notNull": true, "defaultValue": null },
{
"name": "year",
"type": "int64",
"notNull": false,
"defaultValue": {
"type": 2,
"strValue": null,
"longValue": 2024,
"floatValue": 0,
"boolValue": false
}
}
]
}

The HTTP table-creation model accepts string, int64, bool, and id. FLOAT64 is available in SQL.

SQL Execution

Use the SQL endpoints when possible. They exercise the same parser and executor used by the engine tests.

Autocommit SQL requests use Serializable isolation by default. For requests that start an autocommit transaction, isolationLevel can be set to "Serializable" or "ReadCommitted", and transactionMode can be set to "ReadWrite" or "ReadOnly". These fields are ignored when the request resumes an existing transaction with txnIdPT and txnIdCounter.

POST /execute-sql-ddl

For schema-changing SQL:

{
"databaseName": "app",
"sql": "CREATE TABLE IF NOT EXISTS robots (id OID PRIMARY KEY NOT NULL, name STRING NOT NULL, year INT64)",
"parameters": null
}

Server-level database statements can omit databaseName:

{
"sql": "CREATE DATABASE IF NOT EXISTS app",
"parameters": null
}

POST /execute-sql-query

For SELECT statements:

{
"databaseName": "app",
"sql": "SELECT id, name FROM robots WHERE year >= @year ORDER BY name ASC",
"isolationLevel": "Serializable",
"transactionMode": "ReadOnly",
"parameters": {
"@year": {
"type": 2,
"strValue": null,
"longValue": 1970,
"floatValue": 0,
"boolValue": false
}
}
}

Response:

{
"status": "ok",
"total": 1,
"rows": [
{
"id": { "type": 1, "strValue": "507f1f77bcf86cd799439011", "longValue": 0, "floatValue": 0, "boolValue": false },
"name": { "type": 3, "strValue": "R2-D2", "longValue": 0, "floatValue": 0, "boolValue": false }
}
]
}

POST /execute-sql-non-query

For INSERT, UPDATE, and DELETE statements:

{
"databaseName": "app",
"sql": "UPDATE robots SET name = @name WHERE id = @id",
"parameters": {
"@name": { "type": 3, "strValue": "Artoo", "longValue": 0, "floatValue": 0, "boolValue": false },
"@id": { "type": 1, "strValue": "507f1f77bcf86cd799439011", "longValue": 0, "floatValue": 0, "boolValue": false }
}
}

Response:

{
"status": "ok",
"rows": 1
}

Direct Row Operations

Direct endpoints accept filters instead of SQL strings. Filters contain a column name, an operator, and a ColumnValue.

OrderType is also numeric: 0 ascending and 1 descending.

{
"columnName": "year",
"op": ">=",
"value": {
"type": 2,
"strValue": null,
"longValue": 1970,
"floatValue": 0,
"boolValue": false
}
}

POST /insert

{
"databaseName": "app",
"tableName": "robots",
"values": {
"id": { "type": 1, "strValue": "507f1f77bcf86cd799439011", "longValue": 0, "floatValue": 0, "boolValue": false },
"name": { "type": 3, "strValue": "R2-D2", "longValue": 0, "floatValue": 0, "boolValue": false },
"year": { "type": 2, "strValue": null, "longValue": 1977, "floatValue": 0, "boolValue": false }
}
}

POST /query

{
"databaseName": "app",
"tableName": "robots",
"filters": [
{
"columnName": "year",
"op": ">=",
"value": { "type": 2, "strValue": null, "longValue": 1970, "floatValue": 0, "boolValue": false }
}
],
"orderBy": [
{ "columnName": "year", "type": 1 }
]
}

POST /query-by-id

{
"databaseName": "app",
"tableName": "robots",
"id": "507f1f77bcf86cd799439011"
}

POST /update

{
"databaseName": "app",
"tableName": "robots",
"values": {
"name": { "type": 3, "strValue": "Artoo", "longValue": 0, "floatValue": 0, "boolValue": false }
},
"filters": [
{
"columnName": "id",
"op": "=",
"value": { "type": 1, "strValue": "507f1f77bcf86cd799439011", "longValue": 0, "floatValue": 0, "boolValue": false }
}
]
}

POST /delete

{
"databaseName": "app",
"tableName": "robots",
"filters": [
{
"columnName": "year",
"op": "<",
"value": { "type": 2, "strValue": null, "longValue": 1970, "floatValue": 0, "boolValue": false }
}
]
}

Explicit Transactions

Start a transaction:

POST /start-transaction

{
"databaseName": "app",
"isolationLevel": "Serializable",
"transactionMode": "ReadWrite"
}

isolationLevel and transactionMode are optional. If omitted, the transaction starts with the server default isolation level, which is Serializable, and the default transaction mode, which is read-write.

Use "ReadCommitted" only when you intentionally opt down from the default Serializable behavior. Use "ReadOnly" with "Serializable" for a stable snapshot transaction.

Response:

{
"status": "ok",
"txnIdPT": 123,
"txnIdCounter": 1
}

Pass txnIdPT and txnIdCounter to subsequent SQL or direct row requests to reuse that transaction:

{
"databaseName": "app",
"txnIdPT": 123,
"txnIdCounter": 1,
"sql": "INSERT INTO robots (id, name) VALUES (GEN_ID(), \"K-2SO\")"
}

Commit or roll back:

POST /commit-transaction

{
"databaseName": "app",
"txnIdPT": 123,
"txnIdCounter": 1
}

POST /rollback-transaction

{
"databaseName": "app",
"txnIdPT": 123,
"txnIdCounter": 1
}