Records Overview
Every table you declare automatically exposes a complete REST API for its records. There is no resolver to write and no endpoint to register — the moment a table exists in your config, its records collection is reachable under /api/tables/:tableId/records. This page documents the shared API surface: the URL layout, the response envelope, authorship metadata, and the cross-cutting rules (authentication, permissions, formatting) that every records endpoint obeys.
Records are the rows of a table. Tables define the columns (fields); records hold the values. The Records API is the canonical read/write path for that data — pages render it, forms write to it, automations react to it, and external integrations consume it.
Endpoint surface
:tableId accepts either the numeric table id or the table name/slug. All endpoints accept and return JSON.
| Method & Path | Description |
|---|---|
POST /api/tables/:tableId/records |
Create a single record |
GET /api/tables/:tableId/records |
List records (pagination, sort, filter, field-select, group, aggregate) |
GET /api/tables/:tableId/records/:recordId |
Read a single record by ID |
PATCH /api/tables/:tableId/records/:recordId |
Update a single record (partial) |
DELETE /api/tables/:tableId/records/:recordId |
Soft delete a record (?permanent=true to hard delete) |
POST /api/tables/:tableId/records/upsert |
Create-or-update by match fields |
POST /api/tables/:tableId/records/batch |
Batch create |
PATCH /api/tables/:tableId/records/batch |
Batch update |
DELETE /api/tables/:tableId/records/batch |
Batch (soft) delete |
POST /api/tables/:tableId/records/:recordId/restore |
Restore a soft-deleted record |
POST /api/tables/:tableId/records/batch/restore |
Batch restore |
GET /api/tables/:tableId/records/:recordId/history |
Record change history |
GET|POST|PATCH|DELETE /api/tables/:tableId/records/:recordId/comments |
Record comments |
GET /api/tables/:tableId/trash |
Browse soft-deleted records (trash view) |
GET /api/tables/:tableSlug/subscribe |
Real-time WebSocket subscription |
Detailed behavior is split across focused pages: CRUD & upsert, filtering, sorting & pagination, batch operations, history & comments, soft delete & trash, real-time subscriptions, and import/export.
The fields envelope
Record write bodies use the canonical Airtable-style envelope: a fields object mapping field names to values.
POST /api/tables/contacts/records
{
"fields": {
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe"
}
}A successful create returns 201 Created with the stored record, including its generated id and authorship metadata:
{
"id": "42",
"fields": {
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe"
},
"createdBy": "user-uuid-123",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T10:30:00Z"
}Flat bodies are accepted too. A body without a fields key (e.g. { "email": "john@example.com" }) is automatically wrapped into the canonical { "fields": { ... } } shape. The envelope form is preferred and is the only shape accepted by batch and upsert endpoints.
A record from a table declaring AI fields carries one more sibling of fields: an _aiCompute block reporting whether each AI value is the model's answer or the locally computed fallback. It is omitted entirely for every other table.
List response envelope
GET .../records returns a paginated envelope, never a bare array:
{
"records": [{ "id": "1", "fields": {} }],
"pagination": { "total": 128, "limit": 20, "offset": 0 }
}records is the page of results; pagination carries the total matching-row count plus the limit/offset that produced this page. See Filtering, Sorting & Pagination for the full query-parameter grammar.
Authorship metadata
The API automatically stamps and exposes authorship on every write. These fields are server-controlled and read-only — values supplied in a request body are ignored, so the audit trail cannot be forged.
| Field | Set when | Cleared/updated |
|---|---|---|
createdBy / createdAt |
Record is created | Never changes |
updatedBy / updatedAt |
Record is created or updated | Re-stamped on each write |
deletedBy / deletedAt |
Record is soft-deleted | Cleared on restore |
createdBy, updatedBy, and deletedBy resolve to the authenticated user's ID. They are surfaced through dedicated user-audit field types (created-by, updated-by, deleted-by) and the updated-at system field auto-bumps the timestamp on every write — enabling the optimistic-locking contract.
Cross-cutting rules
Every records endpoint enforces the same guarantees:
| Concern | Behavior |
|---|---|
| Authentication | Endpoints require a session. Unauthenticated requests return 401. |
| Table existence | An unknown :tableId returns 404 — never a 403, to avoid enumeration. |
| RBAC | Create/read/update/delete are gated per table permission and the role's RBAC grants. |
| Field-level permissions | Responses omit fields the caller cannot read; writes to fields the caller cannot write are rejected. |
| Validation | Field values are validated against the field type; missing required fields and constraint violations return 400. |
| Anti-enumeration | Unauthorized access to an existing record returns 404, not 403, so an attacker cannot distinguish "forbidden" from "absent". |
404 over 403 is intentional. To prevent record enumeration, the API returns 404 Not Found for records the caller may not access — identical to the response for records that do not exist. See the authentication overview.
Display vs raw formatting
By default, field values are returned raw (the stored value). Pass ?format=display to receive human-readable, locale- and timezone-aware values (formatted currency, dates, durations, attachment display names). The raw form is preferred for programmatic clients; the display form is preferred for direct rendering. See Record formatting for the controls.
Related pages
- CRUD & Upsert — create, read, update, delete, upsert, formatting
- Filtering, Sorting & Pagination — query parameters
- Batch Operations — bulk create/update/delete
- Record History & Comments — change log and collaboration
- Soft Delete & Restore — trash and recovery
- Real-Time Subscriptions — WebSocket/SSE/poll
- Import & Export — CSV/JSON and clipboard
- API Reference — the generated endpoint catalog
Last updated August 11, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.