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
/api/v1/vcaas/projects/:projectId/database/tables-structureFreeRetrieve all database table definitions including field names, types, and configuration.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project ID |
Response fields
| Field | Type | Description |
|---|---|---|
data.tables | array | Array of table definitions |
data.tables[]._id | string | Table ID |
data.tables[].type | string | Table name (snake_case) |
data.tables[].label | string | Human-friendly display name |
data.tables[].description | string | Table description |
data.tables[].icon | string | FontAwesome icon class |
data.tables[].properties | object | Map of property name to property definition |
data.tables[].properties.{name}.id | string | Property ID |
data.tables[].properties.{name}.name | string | Property field name |
data.tables[].properties.{name}.propertyType | string | "string" | "number" | "date" | "options" | "file" | "long-string" | "objectReference" |
data.tables[].properties.{name}.label | string | Human-friendly field label |
data.tables[].properties.{name}.description | string | Field description |
data.tables[].properties.{name}.objectReference | object | Relationship config (if objectReference type) |
data.tables[].properties.{name}.typeExtras | object | Type-specific config (options values, date settings, etc.) |
Example request
curl -H "api-key: tlm_sk_your_key" \
https://api-accounts.totalum.app/api/v1/vcaas/projects/my-app/database/tables-structure{
"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" } }
}
}
}
]
}
}{
"errors": {
"errorCode": "PROJECT_NOT_FOUND",
"errorMessage": "Project does not exist or you don't own it"
},
"data": null
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
MISSING_PROJECT_ID | 400 | projectId is required |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
#Query Database
/api/v1/vcaas/projects/:projectId/database/queryFreeQuery records from any table with advanced filtering, sorting, pagination, aggregations, and nested related data up to 6 levels deep.
Path parameters
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project ID |
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
tableName | string | Yes | The table name to query (use type from tables-structure response) |
queryOptions | object | No | Advanced query options |
queryOptions._filter | object | No | Field filters (see filter operators below) |
queryOptions._sort | object | No | Sort by fields: { fieldName: "asc" | "desc" } |
queryOptions._limit | number | No | Max records to return (default 50, max 1000) |
queryOptions._offset | number | No | Records to skip (for pagination) |
queryOptions._select | object | No | Include only specified fields: { fieldName: true }. Cannot use with _omit |
queryOptions._omit | object | No | Exclude specified fields: { fieldName: true }. Cannot use with _select |
queryOptions._count | boolean | No | Adds _count._total with total matching records (before pagination) |
queryOptions._aggregate | object | No | Aggregations: { _sum: { field: true }, _avg, _min, _max, _count } |
queryOptions._groupBy | string | string[] | No | Group results by field(s). Requires _aggregate |
queryOptions.[property] | true | object | No | Expand related data. true = all fields, object = nested queryOptions |
Filter operators (use inside _filter)
- Exact match:
{ "status": "active" } - With operator:
{ "fieldName": { "operator": value } }
| Operator | Description | Example |
|---|---|---|
gte | Greater than or equal | { "age": { "gte": 18 } } |
lte | Less than or equal | { "age": { "lte": 65 } } |
gt | Greater than | { "price": { "gt": 0 } } |
lt | Less than | { "price": { "lt": 100 } } |
ne | Not equal | { "status": { "ne": "deleted" } } |
in | Matches any value in array | { "status": { "in": ["active", "pending"] } } |
nin | Matches none in array | { "role": { "nin": ["admin", "super"] } } |
regex | Regex pattern (+options for flags) | { "email": { "regex": "@gmail", "options": "i" } } |
contains | Case-insensitive contains | { "name": { "contains": "john" } } |
startsWith | Case-insensitive starts with | { "name": { "startsWith": "J" } } |
endsWith | Case-insensitive ends with | { "email": { "endsWith": ".com" } } |
_or | OR 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
| Field | Type | Description |
|---|---|---|
data.results | array | Array of matching records |
Example request
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{
"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"
}
]
}
}{
"errors": {
"errorCode": "MISSING_TABLE_NAME",
"errorMessage": "tableName is required"
},
"data": null
}More filter examples
// 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
| Code | HTTP | Meaning |
|---|---|---|
MISSING_PROJECT_ID | 400 | projectId is required |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
MISSING_TABLE_NAME | 400 | tableName is required |
#Create Database Record
/api/v1/vcaas/projects/:projectId/database/recordsFreeCreate 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
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project ID |
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
tableName | string | Yes | The table name to insert into (use type from tables-structure response) |
data | object | Yes | The record properties as key-value pairs. Do NOT include _id (auto-generated) |
Response fields
| Field | Type | Description |
|---|---|---|
data | object | The full created record including the auto-generated _id and all fields |
data._id | string | The auto-generated unique identifier for the new record |
Example request
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{
"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"
}
}{
"errors": {
"errorCode": "MISSING_DATA",
"errorMessage": "data is required and must be an object"
},
"data": null
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
MISSING_PROJECT_ID | 400 | projectId is required |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
MISSING_TABLE_NAME | 400 | tableName is required |
MISSING_DATA | 400 | data is required and must be an object |
TABLE_NOT_FOUND | 400 | Table doesn't exist in the project |
#Edit Database Record
/api/v1/vcaas/projects/:projectId/database/records/:recordIdFreeUpdate 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
| Parameter | Type | Description |
|---|---|---|
projectId | string | The project ID |
recordId | string | The _id of the record to update |
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
tableName | string | Yes | The table name (use type from tables-structure response) |
data | object | Yes | The properties to update as key-value pairs. Only included fields are modified |
Response fields
| Field | Type | Description |
|---|---|---|
data | object | The full updated record with all fields (including unchanged ones) |
data._id | string | The record ID |
Example request
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{
"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"
}
}{
"errors": {
"errorCode": "PROJECT_NOT_FOUND",
"errorMessage": "Project does not exist or you don't own it"
},
"data": null
}Error codes
| Code | HTTP | Meaning |
|---|---|---|
MISSING_PROJECT_ID | 400 | projectId is required |
PROJECT_NOT_FOUND | 404 | Project does not exist or you don't own it |
MISSING_RECORD_ID | 400 | recordId is required |
MISSING_TABLE_NAME | 400 | tableName is required |
MISSING_DATA | 400 | data is required and must be an object |
TABLE_NOT_FOUND | 400 | Table doesn't exist in the project |
