Database API

2026-10-22

Database API

Database is a headless content store: structured tables and rows that people, agents and scripts read and write directly through the API, the way a headless CMS works. Concepts and behavior follow Supabase (PostgREST filters, projections, ordering and row writes via supabase-js), so Supabase experience applies. Differences: storage uses SQLite, not PostgreSQL, and schema changes use table/field APIs rather than SQL migrations or raw SQL; access uses a Praxis credential scoped to its tenant, with no Supabase Auth or row-level security policies; realtime row subscriptions are unavailable; casts, aggregates, spread and join modifiers are unsupported, and filtered planned/estimated counts may be unknown; upsert targets id or one unique field rather than composite keys. For an application's own runtime data, use the application's own d1, kv or r2 components instead. Start with praxis.database.databases.create to create a database, then use its returned id for tables and rows.

Use your API Key as a Bearer credential to manage databases and table structure.

https://api.deepraxis.ai/database/v1

Guide →

ResourcePath
Databases/database/v1/databases
Tables/database/v1/databases/{database_id}/tables
Fields/database/v1/databases/{database_id}/tables/{table}/fields
Events/database/v1/databases/{database_id}/events
REST/database/v1/databases/{database_id}/rest/{table}

Error codes

Databases

Guide →

Base URL and authentication

Create database

POST /database/v1/databases

Request body

FieldTypeRequiredDescription
namestringyesDisplay name for the database: 1–64 visible characters after trimming; control characters are rejected. It is not an identifier, so later calls still use the returned id.
labelsobjectnoOptional string tags to attach, at most 64. Each key starts with a lowercase letter and may use up to 63 characters of a-z 0-9 _ -; each value is up to 63 characters of a-z 0-9 _ -. List calls filter on exact key and value pairs.

Returns: Database.

Response

HTTP 201

Success

application/json

NameTypeDescription
idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
namestringDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
curl -X POST "https://api.deepraxis.ai/database/v1/databases" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"walk-lib-r1-DOC-5320-tasks","labels":{"purpose":"docs","sample":"walk-lib-r1-doc-5320-"}}'

Response example — HTTP 201

{
  "id": "db_d6f0d743d5a645e8",
  "name": "walk-lib-r1-DOC-5320-tasks",
  "labels": {
    "purpose": "docs",
    "sample": "walk-lib-r1-doc-5320-"
  },
  "status": "active",
  "table_count": 0,
  "size_bytes": 53248,
  "created_at": "2026-10-11T17:41:40.620Z",
  "updated_at": "2026-10-11T17:41:41.488Z",
  "deleted_at": null,
  "purge_at": null
}

List databases

GET /database/v1/databases

ParameterLocationDescription
cursorqueryOpaque next_cursor from the previous page.
limitqueryPage size. (default: 20) (1–100)
labelsqueryExact label match, encoded as labels[purpose]=docs.
statusqueryFilter by lifecycle state. active (the default when omitted) lists usable databases; deleting lists databases that were deleted and are still inside the seven-day restore window. Any other value returns 400 INVALID_PARAMS.

Returns: Page + object.

Response

HTTP 200

Success

application/json

NameTypeDescription
dataarray<object>Databases on this page, newest first (created_at descending, ties by id). Deleting databases are excluded unless status=deleting.
data[].idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
data[].namestringDisplay name given at creation or by the last update; it is not an identifier.
data[].labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
data[].statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
data[].table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
data[].size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
data[].created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
data[].updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
data[].deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
data[].purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
next_cursorstring | nullOpaque cursor for the next page, or null when there are no more items. Databases list: pass it as cursor. Events list: pass it as after_seq (order asc) or before_seq (order desc).
curl -g -X GET "https://api.deepraxis.ai/database/v1/databases?limit=10&labels[purpose]=docs&labels[sample]=walk-lib-r1-doc-5320-" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "data": [
    {
      "id": "db_d6f0d743d5a645e8",
      "name": "walk-lib-r1-DOC-5320-tasks",
      "labels": {
        "purpose": "docs",
        "sample": "walk-lib-r1-doc-5320-"
      },
      "status": "active",
      "table_count": 0,
      "size_bytes": 53248,
      "created_at": "2026-10-11T17:41:40.620Z",
      "updated_at": "2026-10-11T17:41:41.488Z",
      "deleted_at": null,
      "purge_at": null
    }
  ],
  "next_cursor": null
}

Get database

GET /database/v1/databases/{database_id}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Returns: Database.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
namestringDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
curl -X GET "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "db_d6f0d743d5a645e8",
  "name": "walk-lib-r1-DOC-5320-tasks",
  "labels": {
    "purpose": "docs",
    "sample": "walk-lib-r1-doc-5320-"
  },
  "status": "active",
  "table_count": 0,
  "size_bytes": 53248,
  "created_at": "2026-10-11T17:41:40.620Z",
  "updated_at": "2026-10-11T17:41:41.488Z",
  "deleted_at": null,
  "purge_at": null
}

Update database

PATCH /database/v1/databases/{database_id}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Request body

FieldTypeRequiredDescription
namestringnoNew display name, 1–64 visible characters after trimming. Omit it to keep the current name.
labelsobjectnoComplete replacement label set, not a merge: labels not listed here are removed. Same limits as at creation (at most 64; keys a-z 0-9 _ - starting with a letter; values up to 63 characters of a-z 0-9 _ -). Omit it to keep the current labels.

Returns: Database.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
namestringDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
curl -X PATCH "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"walk-lib-r1-DOC-5320-notes"}'

Response example — HTTP 200

{
  "id": "db_d6f0d743d5a645e8",
  "name": "walk-lib-r1-DOC-5320-notes",
  "labels": {
    "purpose": "docs",
    "sample": "walk-lib-r1-doc-5320-"
  },
  "status": "active",
  "table_count": 0,
  "size_bytes": 53248,
  "created_at": "2026-10-11T17:41:40.620Z",
  "updated_at": "2026-10-11T17:41:43.514Z",
  "deleted_at": null,
  "purge_at": null
}

Delete database

DELETE /database/v1/databases/{database_id}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Returns: Database.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
namestringDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
curl -X DELETE "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "db_d6f0d743d5a645e8",
  "name": "walk-lib-r1-DOC-5320-notes",
  "labels": {
    "purpose": "docs",
    "sample": "walk-lib-r1-doc-5320-"
  },
  "status": "deleting",
  "table_count": 0,
  "size_bytes": 53248,
  "created_at": "2026-10-11T17:41:40.620Z",
  "updated_at": "2026-10-11T17:41:51.868Z",
  "deleted_at": "2026-10-11T17:41:51.868Z",
  "purge_at": "2026-10-18T17:41:51.868Z"
}

Restore database

POST /database/v1/databases/{database_id}/restore

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Returns: Database.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.
namestringDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectString tags attached to the database, as key and value pairs; empty object when none.
statusstringLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegerNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegerStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atstringTime the database was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atstring | nullTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atstring | nullPermanent deletion deadline for deleting databases; null otherwise.
curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/restore" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "db_d6f0d743d5a645e8",
  "name": "walk-lib-r1-DOC-5320-notes",
  "labels": {
    "purpose": "docs",
    "sample": "walk-lib-r1-doc-5320-"
  },
  "status": "active",
  "table_count": 0,
  "size_bytes": 53248,
  "created_at": "2026-10-11T17:41:40.620Z",
  "updated_at": "2026-10-11T17:41:51.528Z",
  "deleted_at": null,
  "purge_at": null
}

Purge database

POST /database/v1/databases/{database_id}/purge

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Returns: object.

Response

HTTP 200

Permanently purged

application/json

NameTypeDescription
idstringId (db_…) of the database that was permanently purged; it no longer resolves.
objectstringResource type of the purged object; always database.
purgedbooleanAlways true: the database and all of its data were permanently removed and cannot be recovered.
curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/purge" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "db_d6f0d743d5a645e8",
  "object": "database",
  "purged": true
}

Database

FieldTypeRequiredDescription
idstringyesDatabase identifier, prefixed db_. Pass it as database_id in every database, table, field, rows and events path.; ^db_
namestringyesDisplay name given at creation or by the last update; it is not an identifier.
labelsobjectyesString tags attached to the database, as key and value pairs; empty object when none.
status"provisioning" / "active" / "deleting" / "deleted" / "failed"yesLifecycle state of the database. Table, field and row calls work only while it is active.
table_countintegeryesNumber of tables currently in the database, at most 50; refreshed when the schema changes.
size_bytesintegeryesStorage size; row writes and GET refresh usage at most once per five seconds, schema changes refresh immediately.
created_atdate-timeyesTime the database was created, as an RFC 3339 UTC timestamp.
updated_atdate-timeyesTime of the last change to the name, labels, status or usage snapshot, as an RFC 3339 UTC timestamp.
deleted_atdate-time / nullyesTime the database entered the deleting state, as an RFC 3339 UTC timestamp; null while it is active and again after a restore.
purge_atdate-time / nullyesPermanent deletion deadline for deleting databases; null otherwise.

Page

FieldTypeRequiredDescription
dataJSON[]yesItems of this page; the item type depends on the operation.
next_cursorstring / nullyesOpaque cursor for the next page, or null when there are no more items. Databases list: pass it as cursor. Events list: pass it as after_seq (order asc) or before_seq (order desc).

Tables

Guide →

Base URL and authentication

Create table

POST /database/v1/databases/{database_id}/tables

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Request body

FieldTypeRequiredDescription
namestringyesTable name used in the rows path and in link references. Must match ^[a-z_][a-z0-9_]{0,62}$ and be unused in this database; it can be renamed later without affecting data.; ^[a-z_][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note describing what the table stores. Returned as description on the table; omit it to store null.
fieldsNewField[]yesInitial field definitions, in display order; may be an empty array. At most 64 fields per table and at most 16 indexed or unique fields. Each item follows the NewField shape selected by its type.

Returns: Table.

Response

HTTP 201

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"tasks","fields":[{"name":"title","type":"string","required":true,"unique":true},{"name":"done","type":"boolean"}]}'

Response example — HTTP 201

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": null,
  "schema_revision": 1,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:44.246Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    }
  ]
}

List tables

GET /database/v1/databases/{database_id}/tables

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.

Returns: Page + object.

Response

HTTP 200

Success

application/json

NameTypeDescription
dataarray<object>Every table of the database with its fields, in creation order; at most 50 items.
data[].idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
data[].namestringCurrent table name, usable in the rows path; may change when the table is renamed.
data[].descriptionstring | nullFree-text note about the table, or null when none was set.
data[].fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
data[].schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
data[].created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
data[].updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
data[].row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
next_cursorstring | nullOpaque cursor for the next page, or null when there are no more items. Databases list: pass it as cursor. Events list: pass it as after_seq (order asc) or before_seq (order desc).
curl -X GET "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "data": [
    {
      "id": "tbl_2b3431c772754599",
      "name": "tasks",
      "description": null,
      "schema_revision": 1,
      "created_at": "2026-10-11T17:41:44.246Z",
      "updated_at": "2026-10-11T17:41:44.246Z",
      "fields": [
        {
          "id": "fld_bc71f7c6a1a848d2",
          "name": "title",
          "type": "string",
          "description": null,
          "required": true,
          "unique": true,
          "indexed": true
        },
        {
          "id": "fld_c7879883dfe04ca0",
          "name": "done",
          "type": "boolean",
          "description": null,
          "required": false,
          "unique": false,
          "indexed": true
        }
      ]
    }
  ],
  "next_cursor": null
}

Get table

GET /database/v1/databases/{database_id}/tables/{table}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.

Returns: Table.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X GET "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": null,
  "schema_revision": 1,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:44.246Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    }
  ],
  "row_count": 0
}

Update table

PATCH /database/v1/databases/{database_id}/tables/{table}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.

Request body

FieldTypeRequiredDescription
namestringnoNew table name matching ^[a-z_][a-z0-9_]{0,62}$ and unused in this database. Omit it to keep the current name.
descriptionstring / nullnoNew description text, or null to clear it. Omit it to keep the current description.

Returns: Table.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X PATCH "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"Tasks for an agent"}'

Response example — HTTP 200

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": "Tasks for an agent",
  "schema_revision": 2,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:45.127Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    }
  ]
}

Delete table

DELETE /database/v1/databases/{database_id}/tables/{table}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.

Returns: object.

Response

HTTP 200

Success

application/json

NameTypeDescription
deletedbooleanAlways true: the table and all of its rows were dropped immediately and cannot be recovered.
curl -X DELETE "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "deleted": true
}

Table

FieldTypeRequiredDescription
idstringyesTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.; ^tbl_
namestringyesCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring / nullyesFree-text note about the table, or null when none was set.
fieldsField[]yesField definitions of the table, in display order. Row values are keyed by each field's name.
schema_revisionintegeryesCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atdate-timeyesTime the table was created, as an RFC 3339 UTC timestamp.
updated_atdate-timeyesTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegernoNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.

Field · Page

Fields

Guide →

Base URL and authentication

Adding, updating or deleting a field returns the complete Table. Field types and link targets are immutable. JSON Schema updates apply to subsequent writes.

A new field with a default fills every existing row with it, required or not, without changing row versions; a new field without a default is null on existing rows. Adding a required field to a table that already has rows needs a default; without one the request returns 400 VALIDATION_FAILED. Making a field required while some rows are null in it returns 400 VALIDATION_FAILED, with the number of null rows in the message. A PATCH with an empty body, only ignored keys, or only values equal to the current ones changes neither updated_at nor schema_revision, records no event and returns the current object.

A datetime default can be the string "now()": insertion evaluates it to current server UTC time, while the field definition still returns "now()". Example: {"name":"created_at","type":"datetime","default":"now()"}. String/json fields keep the literal; other types retain normal validation. Adding a field also evaluates this default when backfilling existing rows.

Add field

POST /database/v1/databases/{database_id}/tables/{table}/fields

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.

Request body

"string" / "integer" / "number" / "boolean" / "datetime"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"string" / "integer" / "number" / "boolean" / "datetime"yesScalar data type of the field; it cannot be changed after the field is created.
optionsobjectnoScalar fields take no options; always an empty object.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"json"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"json"yesType json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created.
optionsobjectyesSettings of a json field. schema is required.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"link"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"link"yesType link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
optionsobjectyesSettings of a link field. Both linked_table_id and multiple are required.

Returns: Table.

Response

HTTP 201

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks/fields" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"priority","type":"integer"}'

Response example — HTTP 201

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": "Tasks for an agent",
  "schema_revision": 3,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:45.420Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    },
    {
      "id": "fld_4c3e63869e35458c",
      "name": "priority",
      "type": "integer",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    }
  ]
}

Update field

PATCH /database/v1/databases/{database_id}/tables/{table}/fields/{field}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.
fieldpathfield ID or name.

Request body

FieldTypeRequiredDescription
namestringnoNew field name (lowercase letters, digits and underscores; id and names starting with _ are reserved). Renaming does not rewrite stored rows. Omit it to keep the current name.
descriptionstring / nullnoNew description text, or null to clear it. Omit it to keep the current description.
requiredbooleannoWhether every row must hold a non-null value for this field. Setting true fails with 400 VALIDATION_FAILED while existing rows have null for the field; fill them first.
indexedbooleannoWhether to maintain an index on this field to speed up filters and ordering. Only scalar fields (string, integer, number, boolean, datetime) can be indexed; true on json or link fields is rejected, and a table allows at most 16 indexed or unique fields.
optionsobjectnoType-specific settings. Only json fields accept changes, through options.schema; scalar fields take no options, and a link field's options cannot change.
defaultJSONnoSets the default for future inserts. Must match the current type and JSON schema; not supported for link fields.

Returns: Table.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X PATCH "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks/fields/priority" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"Task priority"}'

Response example — HTTP 200

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": "Tasks for an agent",
  "schema_revision": 4,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:46.276Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    },
    {
      "id": "fld_4c3e63869e35458c",
      "name": "priority",
      "type": "integer",
      "description": "Task priority",
      "required": false,
      "unique": false,
      "indexed": true
    }
  ]
}

Delete field

DELETE /database/v1/databases/{database_id}/tables/{table}/fields/{field}

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
tablepathtable ID or name.
fieldpathfield ID or name.

Returns: Table.

Response

HTTP 200

Success

application/json

NameTypeDescription
idstringTable identifier, prefixed tbl_. Stable across renames and accepted wherever a table path parameter takes an id or name.
namestringCurrent table name, usable in the rows path; may change when the table is renamed.
descriptionstring | nullFree-text note about the table, or null when none was set.
fieldsarray<object>Field definitions of the table, in display order. Row values are keyed by each field's name.
fields[].idstringField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
fields[].namestringCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
fields[].descriptionstring | nullFree-text note about the field, or null when none was set.
fields[].requiredbooleanWhether every row must hold a non-null value for this field.
fields[].uniquebooleanWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
fields[].indexedbooleanWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
fields[].typestringScalar data type of the field; it cannot be changed after the field is created. / Type json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created. / Type link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
fields[].optionsobjectScalar fields take no options; always an empty object. / Settings of a json field. schema is required. / Settings of a link field. Both linked_table_id and multiple are required.
fields[].defaultanyDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.
schema_revisionintegerCounter that starts at 1 and increases by one each time the table's name, description or fields change; use it to detect schema changes.
created_atstringTime the table was created, as an RFC 3339 UTC timestamp.
updated_atstringTime of the last schema change to the table, as an RFC 3339 UTC timestamp.
row_countintegerNumber of rows currently stored. Returned only by databaseGetTable; absent from list, create and field responses.
curl -X DELETE "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/tables/tasks/fields/priority" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "id": "tbl_2b3431c772754599",
  "name": "tasks",
  "description": "Tasks for an agent",
  "schema_revision": 5,
  "created_at": "2026-10-11T17:41:44.246Z",
  "updated_at": "2026-10-11T17:41:47.136Z",
  "fields": [
    {
      "id": "fld_bc71f7c6a1a848d2",
      "name": "title",
      "type": "string",
      "description": null,
      "required": true,
      "unique": true,
      "indexed": true
    },
    {
      "id": "fld_c7879883dfe04ca0",
      "name": "done",
      "type": "boolean",
      "description": null,
      "required": false,
      "unique": false,
      "indexed": true
    }
  ]
}

Field

"string" / "integer" / "number" / "boolean" / "datetime"

FieldTypeRequiredDescription
idstringyesField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
namestringyesCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
descriptionstring / nullyesFree-text note about the field, or null when none was set.
requiredbooleanyesWhether every row must hold a non-null value for this field.
uniquebooleanyesWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleanyesWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
type"string" / "integer" / "number" / "boolean" / "datetime"yesScalar data type of the field; it cannot be changed after the field is created.
optionsobjectnoScalar fields take no options; always an empty object.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"json"

FieldTypeRequiredDescription
idstringyesField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
namestringyesCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
descriptionstring / nullyesFree-text note about the field, or null when none was set.
requiredbooleanyesWhether every row must hold a non-null value for this field.
uniquebooleanyesWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleanyesWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
type"json"yesType json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created.
optionsobjectyesSettings of a json field. schema is required.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"link"

FieldTypeRequiredDescription
idstringyesField identifier, prefixed fld_. Stable across renames; accepted wherever a field path parameter takes an id or name.
namestringyesCurrent field name; rows are keyed by it in requests and responses. May change when the field is renamed.
descriptionstring / nullyesFree-text note about the field, or null when none was set.
requiredbooleanyesWhether every row must hold a non-null value for this field.
uniquebooleanyesWhether values must be distinct across rows; fixed at creation. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleanyesWhether an index is maintained for faster filters and ordering. Always false for json and link fields.
type"link"yesType link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
optionsobjectyesSettings of a link field. Both linked_table_id and multiple are required.

NewField

"string" / "integer" / "number" / "boolean" / "datetime"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"string" / "integer" / "number" / "boolean" / "datetime"yesScalar data type of the field; it cannot be changed after the field is created.
optionsobjectnoScalar fields take no options; always an empty object.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"json"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"json"yesType json: the value is any JSON document validated against options.schema. It cannot be changed after the field is created.
optionsobjectyesSettings of a json field. schema is required.
defaultJSONnoDefault JSON value for omitted insert fields; must match the field type and JSON schema. A datetime default of "now()" evaluates to server time on insertion and reads back as "now()" in the field definition. For string and json fields it is a literal string. Explicit null remains null. Link fields do not support defaults.

"link"

FieldTypeRequiredDescription
namestringyesField name. Only id is reserved; new field names cannot start with _ (reserved for system metadata). created_at, updated_at and version are ordinary user field names. Existing underscore-prefixed fields remain usable and take precedence over metadata.; ^(?!id$)[a-z][a-z0-9_]{0,62}$
descriptionstringnoOptional free-text note about the field; omit it to store null.
requiredbooleannoWhether every row must hold a non-null value for this field. Defaults to false.
uniquebooleannoWhether values must be distinct across rows. Defaults to false; cannot be changed after the field exists. A unique field is indexed, and a violation returns 409 UNIQUE_VIOLATION.
indexedbooleannoWhether to maintain an index for faster filters and ordering. Defaults to true for scalar types and is not allowed for json and link fields. At most 16 indexed or unique fields per table.
type"link"yesType link: the value is the id of a row in another table (an array of ids when options.multiple is true). It cannot be changed after the field is created.
optionsobjectyesSettings of a link field. Both linked_table_id and multiple are required.

Events

Guide →

Base URL and authentication

Events record database lifecycle and table/field changes, not row reads or writes.

Defaults to ascending seq; before_seq alone implies desc (newest first). next_cursor is an opaque string cursor — pass it back unchanged, as after_seq for asc or before_seq for desc. Both cursors together, or before_seq with order=asc, return 400 INVALID_PARAMS. Events remain readable while a database is deleting.

next_cursor is an opaque string cursor: pass it back unchanged and do not do arithmetic on it. A null next_cursor means there is no next page. The captured response below uses the default ascending order. Descending pagination uses the requests below; live responses for this extension will be added after the service update.

# Newest page
curl "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/events?order=desc&limit=10" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

# Set NEXT_CURSOR to the previous response's next_cursor
curl "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/events?order=desc&before_seq=${NEXT_CURSOR}&limit=10" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

List events

GET /database/v1/databases/{database_id}/events

ParameterLocationDescription
database_idpathIdentifier of the database to act on: the id (db_…) returned by databaseCreateDatabase or databaseListDatabases. A display name is not accepted.
after_seqqueryWith order=asc, return only events with seq greater than this value. Cannot be combined with before_seq.
limitqueryPage size. (default: 50) (1–200)
orderquerySequence order: asc or desc (newest first). Defaults to asc, or to desc when before_seq is supplied.
before_seqqueryReturn only events with seq less than this value, newest first; implies order=desc when order is omitted. Cannot be combined with after_seq or order=asc.

Returns: Page + object.

Response

HTTP 200

Success

application/json

NameTypeDescription
dataarray<object>Events on this page in the requested order (ascending seq by default, newest first with before_seq or order=desc).
data[].seqintegerPosition of the event in the database's event log; starts at 1 and strictly increases. Use it as after_seq or before_seq to page.
data[].idstringUnique identifier of this event record.
data[].typestringWhat happened: a lifecycle transition of the database, or a schema change to a table or field.
data[].processed_atstringTime the event was recorded, as an RFC 3339 UTC timestamp.
data[].database_idstringId (db_…) of the database the event belongs to.
data[].table_idstringId (tbl_…) of the affected table; present only for table and field events.
data[].field_idstringId (fld_…) of the affected field; present only for field events.
next_cursorstring | nullOpaque cursor for the next page, or null when there are no more items. Databases list: pass it as cursor. Events list: pass it as after_seq (order asc) or before_seq (order desc).
curl -X GET "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/events?after_seq=0&limit=10" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response example — HTTP 200

{
  "data": [
    {
      "seq": 1,
      "id": "7390d75e-216c-4799-891e-c043bac8bce5",
      "type": "database.status_provisioning",
      "processed_at": "2026-10-11T17:41:41.339Z",
      "database_id": "db_d6f0d743d5a645e8"
    },
    {
      "seq": 2,
      "id": "39db0ef4-99b4-4846-9d50-9998e25cf48f",
      "type": "database.status_active",
      "processed_at": "2026-10-11T17:41:41.339Z",
      "database_id": "db_d6f0d743d5a645e8"
    },
    {
      "seq": 3,
      "id": "d295651d-5e83-4b42-bcd3-c979fb71f375",
      "type": "table.created",
      "processed_at": "2026-10-11T17:41:44.246Z",
      "database_id": "db_d6f0d743d5a645e8",
      "table_id": "tbl_2b3431c772754599"
    },
    {
      "seq": 4,
      "id": "eb255753-3dd7-4eae-8861-d53408bfcaf4",
      "type": "table.updated",
      "processed_at": "2026-10-11T17:41:45.127Z",
      "database_id": "db_d6f0d743d5a645e8",
      "table_id": "tbl_2b3431c772754599"
    },
    {
      "seq": 5,
      "id": "99c86e22-0629-4391-85e5-d7b8b31de833",
      "type": "field.added",
      "processed_at": "2026-10-11T17:41:45.420Z",
      "database_id": "db_d6f0d743d5a645e8",
      "table_id": "tbl_2b3431c772754599",
      "field_id": "fld_4c3e63869e35458c"
    },
    {
      "seq": 6,
      "id": "a9b85950-363d-4ab3-8c85-6228eec3d099",
      "type": "field.updated",
      "processed_at": "2026-10-11T17:41:46.276Z",
      "database_id": "db_d6f0d743d5a645e8",
      "table_id": "tbl_2b3431c772754599",
      "field_id": "fld_4c3e63869e35458c"
    },
    {
      "seq": 7,
      "id": "73ca124f-6cbb-4a43-8a37-4ff50a211dd5",
      "type": "field.deleted",
      "processed_at": "2026-10-11T17:41:47.136Z",
      "database_id": "db_d6f0d743d5a645e8",
      "table_id": "tbl_2b3431c772754599",
      "field_id": "fld_4c3e63869e35458c"
    }
  ],
  "next_cursor": null
}

DatabaseEvent

FieldTypeRequiredDescription
seqintegeryesPosition of the event in the database's event log; starts at 1 and strictly increases. Use it as after_seq or before_seq to page.
idstringyesUnique identifier of this event record.
type"database.status_provisioning" / "database.status_active" / "database.status_deleting" / "database.status_deleted" / "database.status_failed" / "database.restored" / "table.created" / "table.updated" / "table.deleted" / "field.added" / "field.updated" / "field.deleted"yesWhat happened: a lifecycle transition of the database, or a schema change to a table or field.
processed_atdate-timeyesTime the event was recorded, as an RFC 3339 UTC timestamp.
database_idstringyesId (db_…) of the database the event belongs to.
table_idstringnoId (tbl_…) of the affected table; present only for table and field events.
field_idstringnoId (fld_…) of the affected field; present only for field events.

Read and write rows

Guide →

/database/v1/databases/{database_id}/rest/{table}

Reads and writes the same rows as the other entry point for this database. Errors use PostgREST codes.

Support matrix and client setup

Full parameters, response headers and status codes

One batch POST inserts at most 500 rows. Each request is atomic: a failure in any row rolls back the entire batch. There are no transactions across requests. Put rows that must succeed together in one batch POST. For links, query first, then insert, and handle link errors caused by concurrent changes.

Rows in a batch are filled to the union of their keys with null (PostgREST behavior). Send Prefer: missing=default to use field defaults instead. Explicit null remains null; required fields without defaults must still be provided. The default return=minimal returns 201 with an empty body; send Prefer: return=representation to return rows.

Select rows

GET /database/v1/databases/{database_id}/rest/{table}

curl -X GET "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks?select=*&order=title.asc&limit=10" \
  -H "Authorization: Bearer $PRAXIS_API_KEY"

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

HTTP 206

Partial range with requested count

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

Response example — HTTP 200

HeaderValue
content-range0-0/*
etagW/"5.1"
range-unititems
[
  {
    "id": "rec_3e85a292099340e3",
    "version": 1,
    "created_at": "2026-10-11T17:41:47.896Z",
    "updated_at": "2026-10-11T17:41:47.896Z",
    "title": "Write a summary",
    "done": false
  }
]

Count rows

HEAD /database/v1/databases/{database_id}/rest/{table}

curl --head "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks?select=*" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H 'prefer: count=exact'

Response

HTTP 200

Success; write bodies require Prefer: return=representation

No response body is declared.

HTTP 206

Partial range with requested count

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/1
preference-appliedcount=exact
etagW/"5.1"
range-unititems

No response body.

Insert rows

POST /database/v1/databases/{database_id}/rest/{table}

curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H 'prefer: return=representation' \
  -H "Content-Type: application/json" \
  -d '{"title":"Write a summary","done":false}'

Response

HTTP 201

Success (201). With the default return=minimal the body is empty; Prefer: return=representation returns rows.

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

Response example — HTTP 201

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_3e85a292099340e3",
    "version": 1,
    "created_at": "2026-10-11T17:41:47.896Z",
    "updated_at": "2026-10-11T17:41:47.896Z",
    "title": "Write a summary",
    "done": false
  }
]

Update rows

PATCH /database/v1/databases/{database_id}/rest/{table}

curl -X PATCH "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks?title=eq.Write%20a%20summary" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H 'prefer: return=representation' \
  -H "Content-Type: application/json" \
  -d '{"done":true}'

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

HTTP 204

Success without a body

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_3e85a292099340e3",
    "version": 2,
    "created_at": "2026-10-11T17:41:47.896Z",
    "updated_at": "2026-10-11T17:41:48.802Z",
    "title": "Write a summary",
    "done": true
  }
]

Upsert rows

POST /database/v1/databases/{database_id}/rest/{table}

curl -X POST "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks?on_conflict=title" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H 'prefer: resolution=merge-duplicates,return=representation' \
  -H "Content-Type: application/json" \
  -d '{"title":"Write a summary","done":true}'

Response

HTTP 201

Success (201). With the default return=minimal the body is empty; Prefer: return=representation returns rows.

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

Response example — HTTP 201

HeaderValue
content-range0-0/*
preference-appliedresolution=merge-duplicates, return=representation
range-unititems
[
  {
    "id": "rec_3e85a292099340e3",
    "version": 3,
    "created_at": "2026-10-11T17:41:47.896Z",
    "updated_at": "2026-10-11T17:41:49.076Z",
    "title": "Write a summary",
    "done": true
  }
]

Delete rows

DELETE /database/v1/databases/{database_id}/rest/{table}

curl -X DELETE "https://api.deepraxis.ai/database/v1/databases/${DATABASE_ID}/rest/tasks?title=eq.Write%20a%20summary" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H 'prefer: return=representation'

Response

HTTP 200

Success; write bodies require Prefer: return=representation

application/json

NameTypeDescription
[].idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

application/vnd.pgrst.object+json

NameTypeDescription
idstringRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.

HTTP 204

Success without a body

No response body is declared.

Response example — HTTP 200

HeaderValue
content-range0-0/*
preference-appliedreturn=representation
range-unititems
[
  {
    "id": "rec_3e85a292099340e3",
    "version": 3,
    "created_at": "2026-10-11T17:41:47.896Z",
    "updated_at": "2026-10-11T17:41:49.076Z",
    "title": "Write a summary",
    "done": true
  }
]

Row

Default projections, select=, return=representation and RPC row objects return only id and user fields. Explicitly request metadata with select=,_version,_created_at,_updated_at; star does not expand it. Filter with _version=eq.3 or sort with order=_created_at.desc. Metadata is read-only. Default order remains internal creation time then id. Old filter/order names created_at/updated_at/version without same-named user fields return 400, details use _created_at (or the corresponding name), and hint system metadata moved to underscore columns. Existing underscore user fields take precedence; their same-named system metadata is inaccessible in that table. Historical response examples above were captured before this change and may still contain old metadata columns; this section defines the current row shape.

FieldTypeRequiredDescription
idstringyesRow identifier of 1–64 characters from A-Z a-z 0-9 _ -. Generated by the service unless the insert supplied one; it cannot be changed by updates.; ^[A-Za-z0-9_-]{1,64}$

Error codes

Management endpoints return domain codes; both table endpoints return PostgREST codes. HTTP status and retryability are listed below.

Domain codeHTTPPostgREST codeRetryable
SINGULAR_MISMATCH406PGRST116no
AMBIGUOUS_EMBED300PGRST201no
EMBED_NOT_FOUND400PGRST200no
INVALID_PREFERENCE400PGRST122no
QUERY_CANCELED50057014no
RANGE_NOT_SATISFIABLE416PGRST103no
NOT_ACCEPTABLE406PGRST107no
OPERATOR_TYPE_MISMATCH40042883no
DATABASE_NOT_FOUND404PGRST125no
TABLE_NOT_FOUND404PGRST205no
FIELD_NOT_FOUND40042703no
VALIDATION_FAILED40023514no
UNIQUE_VIOLATION40923505no
REFERENCE_RESTRICT40923503no
FIELD_TYPE_IMMUTABLE400—no
LIMIT_EXCEEDED40054000no
UNSUPPORTED400PGRST127no
INVALID_PARAMS400PGRST100no
DATABASE_INVALID_STATE409—no
CAPACITY503—yes
NOT_IMPLEMENTED501PGRST127no

Retryable does not mean repeating the same request will succeed. For 57014, narrow the query or change its filters before retrying.

Management endpoint error body

Response example — HTTP 400

{
  "code": "FIELD_TYPE_IMMUTABLE",
  "message": "field type is immutable",
  "details": null,
  "hint": null
}

Table endpoint error body

Response example — HTTP 400

{
  "code": "PGRST127",
  "message": "operator fts is not supported",
  "details": null,
  "hint": null
}

The code, message, details and hint fields are always present; details and hint can be null.

Unavailable service error body

Response example — HTTP 501

HeaderValue
x-should-retryfalse
{
  "code": "not_implemented",
  "message": "auth is not provided by praxis-database"
}

These five services return not_implemented directly; this differs from the NOT_IMPLEMENTED domain code in the table.

Correct the request using error details

Only id is a reserved field name. New field names cannot start with _, which is reserved for system metadata. created_at, updated_at and version are ordinary user field names. Datetime fields can use "now()" as a default.

details identifies the field or JSON path and the received value. Batch validation includes a zero-based row index. Values are limited to 80 characters; the entire row is never echoed. hint suggests a correction, or is null when no suggestion applies. This example omits the required title in row 2:

{
  "code": "23514",
  "message": "row validation failed",
  "details": "row 1: title: required value (got null)",
  "hint": "Rows in one insert are filled to the union of their keys with null (PostgREST behavior). Send every key in every row, or send Prefer: missing=default to use field defaults."
}

A unique conflict returns 409, for example:

{
  "code": "23505",
  "message": "unique constraint violated",
  "details": "Key (email)=(a@b.c) already exists.",
  "hint": null
}