Docs
BlogHomeStart building

Database

Read the schema, query with rich filters, and mutate records in your project database.


The database API exposes your project's tables and records. You can read the table structure, query with filtering/sorting/pagination/aggregation and nested relations up to 6 levels deep, and create or edit records. All endpoints require the api-key header and are free.

#Get Database Tables Structure

GET/api/v1/vcaas/projects/:projectId/database/tables-structureFree

Retrieve all database table definitions including field names, types, and configuration.

Path parameters

ParameterTypeDescription
projectIdstringThe project ID

Response fields

FieldTypeDescription
data.tablesarrayArray of table definitions
data.tables[]._idstringTable ID
data.tables[].typestringTable name (snake_case)
data.tables[].labelstringHuman-friendly display name
data.tables[].descriptionstringTable description
data.tables[].iconstringFontAwesome icon class
data.tables[].propertiesobjectMap of property name to property definition
data.tables[].properties.{name}.idstringProperty ID
data.tables[].properties.{name}.namestringProperty field name
data.tables[].properties.{name}.propertyTypestring"string" | "number" | "date" | "options" | "file" | "long-string" | "objectReference"
data.tables[].properties.{name}.labelstringHuman-friendly field label
data.tables[].properties.{name}.descriptionstringField description
data.tables[].properties.{name}.objectReferenceobjectRelationship config (if objectReference type)
data.tables[].properties.{name}.typeExtrasobjectType-specific config (options values, date settings, etc.)

Example request

bash
curl -H "api-key: tlm_sk_your_key" \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/database/tables-structure
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "tables": [
      {
        "_id": "65f1a2b3c4d5e6f7",
        "type": "customers",
        "label": "Customers",
        "description": "Customer records",
        "icon": "fa-solid fa-users",
        "properties": {
          "name": {
            "id": "prop_abc123",
            "name": "name",
            "propertyType": "string",
            "label": "Full Name"
          },
          "email": {
            "id": "prop_def456",
            "name": "email",
            "propertyType": "string",
            "label": "Email",
            "typeExtras": { "string": { "type": "link" } }
          }
        }
      }
    ]
  }
}
Error · 404
json
{
  "errors": {
    "errorCode": "PROJECT_NOT_FOUND",
    "errorMessage": "Project does not exist or you don't own it"
  },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it

#Query Database

POST/api/v1/vcaas/projects/:projectId/database/queryFree

Query records from any table with advanced filtering, sorting, pagination, aggregations, and nested related data up to 6 levels deep.

Path parameters

ParameterTypeDescription
projectIdstringThe project ID

Body parameters

FieldTypeRequiredDescription
tableNamestringYesThe table name to query (use type from tables-structure response)
queryOptionsobjectNoAdvanced query options
queryOptions._filterobjectNoField filters (see filter operators below)
queryOptions._sortobjectNoSort by fields: { fieldName: "asc" | "desc" }
queryOptions._limitnumberNoMax records to return (default 50, max 1000)
queryOptions._offsetnumberNoRecords to skip (for pagination)
queryOptions._selectobjectNoInclude only specified fields: { fieldName: true }. Cannot use with _omit
queryOptions._omitobjectNoExclude specified fields: { fieldName: true }. Cannot use with _select
queryOptions._countbooleanNoAdds _count._total with total matching records (before pagination)
queryOptions._aggregateobjectNoAggregations: { _sum: { field: true }, _avg, _min, _max, _count }
queryOptions._groupBystring | string[]NoGroup results by field(s). Requires _aggregate
queryOptions.[property]true | objectNoExpand related data. true = all fields, object = nested queryOptions

Filter operators (use inside _filter)

  • Exact match: { "status": "active" }
  • With operator: { "fieldName": { "operator": value } }
OperatorDescriptionExample
gteGreater than or equal{ "age": { "gte": 18 } }
lteLess than or equal{ "age": { "lte": 65 } }
gtGreater than{ "price": { "gt": 0 } }
ltLess than{ "price": { "lt": 100 } }
neNot equal{ "status": { "ne": "deleted" } }
inMatches any value in array{ "status": { "in": ["active", "pending"] } }
ninMatches none in array{ "role": { "nin": ["admin", "super"] } }
regexRegex pattern (+options for flags){ "email": { "regex": "@gmail", "options": "i" } }
containsCase-insensitive contains{ "name": { "contains": "john" } }
startsWithCase-insensitive starts with{ "name": { "startsWith": "J" } }
endsWithCase-insensitive ends with{ "email": { "endsWith": ".com" } }
_orOR logic (array of conditions){ "_or": [{ "status": "active" }, { "role": "admin" }] }

Nested queries (related data)

Expand related tables by using the property name as a key in queryOptions.

  • Shorthand: { "orders": true } — expands all related orders
  • Full: { "orders": { "_filter": {...}, "_sort": {...}, "_limit": 5 } } — with options (max 300 children)
  • { "orders": { "_has": true } } — only parents with at least one matching child
  • { "orders": { "_has": "none" } } — only parents with zero matching children
  • { "orders": { "_count": true } } — include child count per parent
  • Nesting up to 6 levels deep supported

Response fields

FieldTypeDescription
data.resultsarrayArray of matching records

Example request

bash
curl -X POST \
  -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"tableName":"customers","queryOptions":{"_filter":{"status":"active","age":{"gte":18}},"_sort":{"createdAt":"desc"},"_limit":10,"orders":{"_filter":{"total":{"gt":50}},"_limit":5}}}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/database/query
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "results": [
      {
        "_id": "65f1a2b3c4d5e6f7a8b9c0d1",
        "name": "John Doe",
        "email": "john@example.com",
        "status": "active",
        "age": 30,
        "orders": [
          { "_id": "...", "total": 120.50, "createdAt": "2026-03-09T..." }
        ],
        "createdAt": "2026-03-10T08:00:00.000Z"
      }
    ]
  }
}
Error · 400
json
{
  "errors": {
    "errorCode": "MISSING_TABLE_NAME",
    "errorMessage": "tableName is required"
  },
  "data": null
}

More filter examples

js
// OR logic
"_filter": { "_or": [{ "status": "active" }, { "role": "admin" }] }
// IN operator
"_filter": { "status": { "in": ["active", "pending"] } }
// Regex case-insensitive
"_filter": { "email": { "regex": "@gmail", "options": "i" } }
// Aggregation with groupBy
"_aggregate": { "_sum": { "total": true }, "_count": true }, "_groupBy": "status"
// Nested: only parents with children matching filter
"orders": { "_has": true, "_filter": { "total": { "gt": 100 } } }

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it
MISSING_TABLE_NAME400tableName is required

#Create Database Record

POST/api/v1/vcaas/projects/:projectId/database/recordsFree

Create a new record in any table. The _id field is auto-generated by the database — do not include it in the request body. The response returns the full created record including the generated _id and any default fields.

Path parameters

ParameterTypeDescription
projectIdstringThe project ID

Body parameters

FieldTypeRequiredDescription
tableNamestringYesThe table name to insert into (use type from tables-structure response)
dataobjectYesThe record properties as key-value pairs. Do NOT include _id (auto-generated)

Response fields

FieldTypeDescription
dataobjectThe full created record including the auto-generated _id and all fields
data._idstringThe auto-generated unique identifier for the new record

Example request

bash
curl -X POST \
  -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"tableName":"customers","data":{"name":"John Doe","email":"john@example.com","status":"active","age":30}}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/database/records
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "_id": "65f1a2b3c4d5e6f7a8b9c0d1",
    "name": "John Doe",
    "email": "john@example.com",
    "status": "active",
    "age": 30,
    "createdAt": "2026-03-25T10:00:00.000Z",
    "updatedAt": "2026-03-25T10:00:00.000Z"
  }
}
Error · 400
json
{
  "errors": {
    "errorCode": "MISSING_DATA",
    "errorMessage": "data is required and must be an object"
  },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it
MISSING_TABLE_NAME400tableName is required
MISSING_DATA400data is required and must be an object
TABLE_NOT_FOUND400Table doesn't exist in the project

#Edit Database Record

PATCH/api/v1/vcaas/projects/:projectId/database/records/:recordIdFree

Update specific fields of an existing record by its ID. Only the fields included in data will be modified — all other fields remain unchanged. The response returns the full updated record.

Path parameters

ParameterTypeDescription
projectIdstringThe project ID
recordIdstringThe _id of the record to update

Body parameters

FieldTypeRequiredDescription
tableNamestringYesThe table name (use type from tables-structure response)
dataobjectYesThe properties to update as key-value pairs. Only included fields are modified

Response fields

FieldTypeDescription
dataobjectThe full updated record with all fields (including unchanged ones)
data._idstringThe record ID

Example request

bash
curl -X PATCH \
  -H "api-key: tlm_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"tableName":"customers","data":{"email":"newemail@example.com","age":31}}' \
  https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/database/records/65f1a2b3c4d5e6f7a8b9c0d1
Success · 200 OK
json
{
  "errors": null,
  "data": {
    "_id": "65f1a2b3c4d5e6f7a8b9c0d1",
    "name": "John Doe",
    "email": "newemail@example.com",
    "status": "active",
    "age": 31,
    "createdAt": "2026-03-25T10:00:00.000Z",
    "updatedAt": "2026-03-25T10:05:00.000Z"
  }
}
Error · 404
json
{
  "errors": {
    "errorCode": "PROJECT_NOT_FOUND",
    "errorMessage": "Project does not exist or you don't own it"
  },
  "data": null
}

Error codes

CodeHTTPMeaning
MISSING_PROJECT_ID400projectId is required
PROJECT_NOT_FOUND404Project does not exist or you don't own it
MISSING_RECORD_ID400recordId is required
MISSING_TABLE_NAME400tableName is required
MISSING_DATA400data is required and must be an object
TABLE_NOT_FOUND400Table doesn't exist in the project