Skip to main content

Database API

CRUD operations on database tables. All database endpoints use the following URL pattern:

/api/db/{namespace}/tables/{tableName}

For dynamic DB blocks with instance IDs:

/api/db/{namespace}/{instanceId}/tables/{tableName}

For example, /api/db/workspace/ws_123/tables/documents targets the documents table in the workspace DB block with instance ID ws_123.

Authentication

Database endpoints respect access rules defined in your EdgeBase configuration. Depending on your rules, requests may require:

  • Bearer Token: Authorization: Bearer <accessToken>
  • Service Key: X-EdgeBase-Service-Key: <serviceKey>
  • Public access: No authentication (if rules allow)

List Records

GET /api/db/shared/tables/:name

Retrieve a list of records from a table. Supports filtering, sorting, and two pagination modes.

Query ParameterTypeExampleDescription
filterJSON[["status","==","published"]]Filter tuple array
sortstringcreatedAt:descSort order (field:asc or field:desc, comma-separated for multiple)
limitnumber20Maximum number of records to return
pagenumber2Page number (offset-based pagination)
perPagenumber20Number of records per page
offsetnumber20Number of records to skip
afterstring01J...Cursor pagination (forward)
beforestring01J...Cursor pagination (backward)
orFilterJSON[["type","==","news"],["featured","==",true]]OR condition filter (maximum 5 conditions)
warning

page/offset and after/before are mutually exclusive. Using both in the same request will result in an error.

Offset-based pagination

When using offset, the response includes pagination metadata: total (total record count), page (computed page number), and perPage (records per page). For example, ?offset=20&limit=10 returns page: 3 and perPage: 10 along with the total count. This is useful for building paginated UIs with page number navigation.

curl "https://your-project.edgebase.dev/api/db/shared/tables/posts?filter=[[\"status\",\"==\",\"published\"]]&sort=createdAt:desc&limit=20" \
-H "Authorization: Bearer <accessToken>"

Response 200 (Offset mode -- default when using page or offset)

{
"items": [
{
"id": "01J...",
"title": "Hello",
"status": "published",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
],
"total": 42,
"page": 1,
"perPage": 20,
"hasMore": null,
"cursor": null
}

Response 200 (Cursor mode -- when using after or before)

{
"items": [
{
"id": "01J...",
"title": "Hello",
"status": "published",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
],
"total": null,
"page": null,
"perPage": null,
"hasMore": true,
"cursor": "01J..."
}

Get Record

GET /api/db/shared/tables/:name/:id

Retrieve a single record by its ID.

Path ParameterDescription
nameTable name
idRecord ID
curl https://your-project.edgebase.dev/api/db/shared/tables/posts/01J... \
-H "Authorization: Bearer <accessToken>"

Response 200

{
"id": "01J...",
"title": "Hello",
"status": "published",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}

Insert Record

POST /api/db/shared/tables/:name

Insert a new record. The following fields are auto-generated if not provided: id (UUID v7), createdAt, and updatedAt.

Path ParameterDescription
nameTable name
curl -X POST https://your-project.edgebase.dev/api/db/shared/tables/posts \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"title": "Hello World",
"status": "draft",
"tags": ["intro", "tutorial"],
"authorId": "01J..."
}'

Response 201

{
"id": "01J...",
"title": "Hello World",
"status": "draft",
"tags": ["intro", "tutorial"],
"authorId": "01J...",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}

Upsert Record

POST /api/db/shared/tables/:name?upsert=true

Insert a new record or update an existing one if a conflict is detected on the specified field.

Query ParameterTypeDefaultDescription
upserttrue--Enable upsert mode
conflictTargetstringidField to check for conflicts
Request BodyTypeRequiredDescription
idstringYesRecord ID (used for conflict check)
(any field)anyData to upsert
curl -X POST "https://your-project.edgebase.dev/api/db/shared/tables/posts?upsert=true" \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"id": "01J...",
"title": "Hello World",
"status": "published"
}'

Response 200 (updated) or 201 (created)

{
"id": "01J...",
"title": "Hello World",
"status": "published",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
Access Rules for Upsert

When upsert=true is set, both insert and update access rules are evaluated. The request passes if either rule allows it.


Update Record

PATCH /api/db/shared/tables/:name/:id

Partially update a record. Supports special field operators for atomic operations.

Path ParameterDescription
nameTable name
idRecord ID
Request BodyTypeDescription
(any field)anyFields to update
{field}: {"$op": "increment", "value": n}objectAtomically increment a numeric field by n
{field}: {"$op": "deleteField"}objectRemove a field (set to NULL)
curl -X PATCH https://your-project.edgebase.dev/api/db/shared/tables/posts/01J... \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Title",
"viewCount": { "$op": "increment", "value": 1 },
"removedField": { "$op": "deleteField" }
}'

Response 200

{
"id": "01J...",
"title": "Updated Title",
"viewCount": 43,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T12:00:00.000Z"
}

Delete Record

DELETE /api/db/shared/tables/:name/:id

Delete a single record by its ID.

Path ParameterDescription
nameTable name
idRecord ID
curl -X DELETE https://your-project.edgebase.dev/api/db/shared/tables/posts/01J... \
-H "Authorization: Bearer <accessToken>"

Response 200

{ "ok": true }

Count Records

GET /api/db/shared/tables/:name/count

Return the count of records matching a filter, without returning the records themselves.

Query ParameterTypeDescription
filterJSONFilter tuple array (same format as list)
curl "https://your-project.edgebase.dev/api/db/shared/tables/posts/count?filter=[[\"status\",\"==\",\"published\"]]" \
-H "Authorization: Bearer <accessToken>"

Response 200

{ "total": 42 }

GET /api/db/shared/tables/:name/search

Perform a full-text search (FTS) query. Requires the table to have fts configured in the schema.

Query ParameterTypeDefaultDescription
qstring--Search query term
limitnumberMaximum number of results
offsetnumberNumber of results to skip
highlightPrestring<mark>Opening highlight tag
highlightPoststring</mark>Closing highlight tag
curl "https://your-project.edgebase.dev/api/db/shared/tables/posts/search?q=hello&highlight=true&limit=10" \
-H "Authorization: Bearer <accessToken>"

Response 200 -- Same format as list endpoint


Batch Operations

POST /api/db/shared/tables/:name/batch

Execute multiple insert, update, and delete operations in a single all-or-nothing transaction. Maximum 500 operations per request.

Request BodyTypeDescription
insertsarrayArray of objects to insert
updatesarrayArray of objects with id to update
deletesarrayArray of record IDs to delete

Append ?upsert=true to enable upsert mode for the inserts and updates. When enabled, each item in the inserts array becomes an upsert — if a record with the same primary key already exists, it is updated instead of causing a conflict error. The same access rule semantics as single upsert apply: both insert and update rules are evaluated, and the request passes if either allows it.

Example: Batch insert

curl -X POST https://your-project.edgebase.dev/api/db/shared/tables/posts/batch \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"inserts": [
{ "title": "Post 1", "status": "draft" },
{ "title": "Post 2", "status": "draft" }
]
}'

Example: Mixed batch

{
"inserts": [
{ "title": "New Post" }
],
"updates": [
{ "id": "01J...", "data": { "title": "Updated Post" } }
],
"deletes": ["01Jabc...", "01Jdef..."]
}

Response 200

{
"inserted": [
{ "id": "01J...", "title": "Post 1", "createdAt": "...", "updatedAt": "..." }
],
"updated": [],
"deleted": []
}

Batch by Filter

POST /api/db/shared/tables/:name/batch-by-filter

Update or delete multiple records matching a filter condition. Maximum 500 records affected per request.

Request BodyTypeRequiredDescription
actionstringYes"update" or "delete"
filterarrayFilter tuple array
orFilterarrayOR condition filter (maximum 5 conditions)
dataobjectData to apply (required when action is "update")

Example: Delete by filter

{
"action": "delete",
"filter": [["status", "==", "draft"]]
}

Example: Update by filter

curl -X POST https://your-project.edgebase.dev/api/db/shared/tables/posts/batch-by-filter \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"action": "update",
"filter": [["status", "==", "draft"]],
"data": { "status": "archived" }
}'

Response 200

{ "processed": 15, "succeeded": 15 }

Filter Syntax

Filters use a tuple array format: [field, operator, value].

OperatorDescriptionExample
==Equal["status", "==", "published"]
!=Not equal["status", "!=", "draft"]
>Greater than["price", ">", 100]
>=Greater than or equal["price", ">=", 100]
<Less than["price", "<", 50]
<=Less than or equal["price", "<=", 50]
containsSubstring match (case-sensitive)["title", "contains", "hello"]
inValue in array["status", "in", ["a", "b"]]
not inValue not in array["status", "not in", ["x"]]

Multiple filter tuples are combined with AND logic:

[["status", "==", "published"], ["authorId", "==", "01J..."]]

Use orFilter for OR conditions (each condition is ORed):

[["status", "==", "published"], ["featured", "==", true]]

Dynamic DB Blocks

For tables in dynamic DB blocks, include the instance ID in the URL path:

GET  /api/db/workspace/ws_123/tables/documents
POST /api/db/user/user_456/tables/preferences

The static shared namespace does not require an instance ID:

GET /api/db/shared/tables/posts

Error Format

All error responses follow this structure:

{
"code": 400,
"message": "Validation failed.",
"data": {
"title": { "code": "required", "message": "Field is required." }
}
}
HTTP StatusMeaning
400Bad request / validation error
401Authentication required
403Access denied (access rule violation)
404Table or record not found
409Conflict (e.g., duplicate ID)
429Rate limit exceeded
500Internal server error