Data model reference
Exhaustive reference for records, schemas, documents, folders, lookups, references, and version history: methods, parameters, field types, validation rules, limits, envelope shape, error codes, and an honest "Notes & limits" for each area.
This page does not reproduce the raw endpoint reference — the full request/response shapes are in the generated API reference (OpenAPI / Scalar). Method names below are the Node SDK sub-client methods. The spec is currently at 0.27.0. PATCH and create-by-
typeName-alone require SDK 0.26+ (bundled in the CLI and MCP server); all other calls also work on a 0.23 client.
Conventions
The list envelope (FC-01)
List, lookup, and version endpoints return a paginated envelope:
{ "data": [ /* items */ ], "nextCursor": "opaque-string-or-null" }
Drain it by feeding nextCursor back as startFrom until it is null. The cursor is
opaque — never construct or offset it. search.content and usage endpoints are not
enveloped (they return their own shapes).
Identifiers
typeName, field ids, and lookup field names share one grammar: ^[A-Za-z0-9_-]{1,64}$
— letters (any case), digits, underscore, hyphen; 1–64 characters. camelCase,
snake_case, PascalCase, and kebab-case are all valid. The names userId, orgId,
and clientId are reserved and may not be redeclared as lookup fields.
Timestamps
Creation and modification timestamps are returned as ISO-8601 UTC strings.
Optimistic concurrency
Records, documents, and folders accept an optional expectedVersion on update/patch.
Supply the version you last read; the write is rejected with 409 VERSION_CONFLICT if
the entity changed since, leaving it untouched. Omit it for last-write-wins.
Schemas — client.schemas.*
| Method | Purpose |
|---|---|
createSchema(body) | Create a schema. |
getSchema({ id }) | Fetch by id. |
updateSchema({ id, body }) | PUT full-replace (no PATCH). |
deleteSchema({ id }) | Delete. |
listSchemas({ startFrom?, limit?, surface? }) | List (FC-01 envelope). |
getSchemaVersions({ id }) | Version history (FC-01 envelope). |
Schema fields
| Field | Type | Required | Notes |
|---|---|---|---|
typeName | string | yes | Immutable after create. Identifier grammar. Unique per tenant+context. |
displayName | string | yes | Human-readable name. |
description | string | no | |
fields | FieldDef[] | no | Omit for a bare schema (no validation). |
lookupFields | LookupDef[] | no | Max 10 (partner-declared); see lookup notes. |
renderHints | map keyed by fieldId | no | UI hints; does not affect storage/validation. |
capabilities | map<string,boolean> | no | auditHistory (default true). |
indexMode | enum | no | HYBRID | SEMANTIC | TEXT | NONE. Type-level default for instances. Omit = no default. |
storageProfile | enum | no | STANDARD (default) | LOW_LATENCY | LARGE_PAYLOAD. |
allowedSurfaces | string[] | yes | Non-empty. Any of record, document, user, org, client. |
active | boolean | no | Default true. Inactive schemas reject new record creation. |
userId / orgId / clientId | string | no | Ownership defaults for the schema itself. |
FieldDef
| Field | Type | Notes |
|---|---|---|
fieldId | string | Required. Identifier grammar. |
fieldType | enum | string | number | boolean | date | enum | array | object | reference. |
required | boolean | Enforced on create. |
searchable | boolean | Field text enters the full-text search lane. |
filterable | boolean | Field available as a search filter (no relevance influence). |
description | string | |
validation | object | Validation rules (below). |
enumValues | array | Allowed values for enum fields. |
sensitive | boolean | Redact-at-write + search-exclusion + read-masking + blind-indexed lookup. |
targetTypeName | string | reference only: the type pointed at (required for references). |
targetField | string | reference only: target lookup field to resolve against (default externalId; must be a unique lookup on the target). |
cardinality | enum | reference only: one (default) | many. |
targetSurface | enum | reference only (required for references): surface the target lives on — record/document/user/org/client. |
Validation rules (the validation object)
required, minLength, maxLength, min, max, pattern, email, url, phone,
step, multipleOf, minItems, maxItems. Rules are enforced at record write; a
violation returns a 400 with a readable message before the record is persisted.
LookupDef
A lookup field is either a bare field name string, or { fieldName, unique }.
unique: true enforces one record per value per tenant+context.
RenderHintDef
label, widget (text | textarea | select | date | checkbox), order,
section, helpText, displayField (marks the headline field; at most one per schema).
Schema versioning
schemaVersion is a public revision counter: 1 on create, prior + 1 on each update.
Records and documents are stamped with the governing schemaVersion at write and keep
that value even after the schema evolves. getSchemaVersions returns the immutable
version-row history (same envelope and row shape as record versions).
Notes & limits — schemas
- No PATCH. Schemas are PUT-replace only. Collection fields (
fields,lookupFields,renderHints,capabilities) are replaced in full on update — supply the complete intended set; omitted scalar fields are preserved. typeNameis immutable after creation.- Creating a schema is idempotent by
typeName. Re-issuingcreateSchemafor atypeNamethat already exists returns the existing schema rather than failing, so a provisioning step that runs twice is safe. To change a schema, update it (PUT-replace). - A bare schema runs no payload validation; all string values are still text-indexed for search when its index mode permits.
- Schema-field reference targets are declarable today; write-time existence/type
enforcement of references is not yet active — a
referencefield carries the link but is not yet validated against the target on write.
Records — client.records.*
| Method | Purpose |
|---|---|
createRecord(body) | Create. typeName and/or schemaId (see below). |
getRecord({ id }) | Fetch by id (always full payload). |
updateRecord({ id, body }) | PUT — replace mutable fields; payload replaced in full. |
patchRecord({ id, body }) | PATCH (RFC 7386). SDK 0.26+. |
deleteRecord({ id }) | Hard delete (+ tombstone). |
listRecords({ type, userId?, orgId?, clientId?, startFrom?, limit?, includePayload? }) | List (FC-01 envelope). |
lookupRecords({ type, field, value? | from?+to? | prefix?, startFrom?, limit?, includePayload? }) | Lookup, one mode (FC-01 envelope). |
lookupRecordsByBody({ ... }) | Body-based lookup (sensitive-safe). |
getRecordVersions({ id }) | Version history (FC-01 envelope). |
getRecordTombstone({ id }) | Tombstone for a deleted record. |
Create / update fields (RecordRequest)
| Field | Type | Notes |
|---|---|---|
typeName | string | The record type. See type-identification below. Immutable; ignored on update. |
schemaId | string | Schema to validate against. See below. Immutable; ignored on update. |
payload | object | Validated against the schema. On PUT, replaces the stored payload in full. |
status | string | Lifecycle/workflow status (default ACTIVE). |
folderId | string | Group with a folder. Cannot currently be cleared once set. |
userId / orgId / clientId | string | Ownership (Vectros UUIDs). Subject to token identity auto-assign. |
externalId | string | Stable partner id. Immutable. Unique within tenant+context+typeName (idempotent create). Max 256 chars. |
indexMode | enum | Per-record override: HYBRID/SEMANTIC/TEXT/NONE. Immutable after create. |
expectedVersion | number | Optimistic concurrency. Ignored on create. |
Type identification (SDK 0.26+ either-or): provide typeName or schemaId
(at least one). With only typeName, the server resolves the schema (record type is
unique per tenant+context). With only schemaId, it resolves the type from the schema.
With both, they must agree. A 0.23 client always sends both.
RecordResponse (selected fields)
id, typeName, schemaId, schemaVersion, externalId, payload,
payloadExternalized, payloadBytes, status, folderId, userId, orgId,
clientId, indexStatus (PENDING_INDEX | INDEXED | FAILED, null for store-only),
indexMode, createdBy, createdAt, updatedAt, version.
For an externalized (large) payload, list/lookup responses return only the indexed
projection and set payloadExternalized: true; fetch the full payload via by-id GET or
pass includePayload: true on the list/lookup call.
Automatic ownership lookups
Every record is automatically lookup-indexed by userId, orgId, and clientId
without declaring them and without counting against the 10-field cap — so
listRecords({ type, userId }) (etc.) resolve directly.
Notes & limits — records
- PUT replaces the payload in full — it is not deep-merged. Use PATCH (0.26+) for a true partial payload update.
- PATCH patchable keys:
payload,status,folderId,userId,orgId,clientId,expectedVersion. Immutable keys (typeName,schemaId,externalId,indexMode) are rejected if present. Withinpayload, a key set tonullis deleted; a top-level patchable field (such asstatusorfolderId) set tonullis not a delete — it is rejected with400. Clearing a top-level field is not supported. typeNameis immutable after creation. To change a record's type, write a new record and delete the old one.folderIdcannot currently be cleared once set.- Delete is hard delete — there is no soft-delete status that lingers in the index.
- Batch write / lookup / get are reserved and not yet implemented (they return a
501 not_implemented). Do not depend on them.
Documents — client.documents.*
| Method | Purpose |
|---|---|
ingestDocument(body) | Inline text ingest. |
uploadDocument(body) | Request a presigned upload URL (file path). |
getDocument({ id }) | Fetch by id. |
getDocumentText({ id }) | Retrieve stored raw text (requires storeText: true). |
getDocumentDownloadUrl({ id }) | Presigned download URL for a file-backed document. |
updateDocument({ id, body }) | PUT — full replace; text re-ingests. |
patchDocument({ id, body }) | PATCH (RFC 7386). SDK 0.26+. |
deleteDocument({ id }) | Hard delete (+ tombstone). |
listDocuments({ userId?, orgId?, clientId?, startFrom?, limit? }) | List (FC-01 envelope). |
lookupDocuments(...) / lookup-by-body | Lookup on a schema-bound document's lookup fields. |
getDocumentVersions({ id }) | Version history (FC-01 envelope). |
Ingest / update fields (DocumentRequest)
| Field | Type | Notes |
|---|---|---|
title | string | Required. |
text | string | Inline ingest body. Required on POST ingest; on PUT/PATCH it re-ingests write-through. |
indexMode | enum | HYBRID/SEMANTIC/TEXT/NONE. Optional if the bound schema sets a default; otherwise required. Fixed at creation. |
storeText | boolean | Default false. When true, the raw text is retrievable via getDocumentText. |
folderId | string | Defaults to the context root. Cannot be cleared once set. |
payload | object | Structured data (records parity). Validated + lookup-indexed when schemaId is set; undeclared keys pass through as free-form, filterable in search. Replaced in full on PUT. |
schemaId | string | Optional schema to validate + lookup-index the payload against. |
userId / orgId / clientId | string | Ownership (Vectros UUIDs). |
externalId | string | Stable partner id. Immutable. Unique within tenant+context (idempotent ingest). Max 256 chars. |
expectedVersion | number | Optimistic concurrency. Ignored on create. |
Upload handshake (uploadDocument)
uploadDocument returns uploadUrl and expiresAt. PUT the raw bytes to uploadUrl
without an Authorization header, set Content-Type to the file's MIME type, then
poll getDocument until status is INDEXED.
DocumentResponse (selected fields)
id, title, externalId, status (PENDING_UPLOAD | UPLOADED | EXTRACTING |
PENDING_INDEX | INDEXED | STORED | FAILED), indexMode, storeText,
folderId, payload, payloadExternalized, schemaId, schemaVersion, textBytes,
userId, orgId, clientId, fileType, fileSize, createdAt, lastModified,
version.
Notes & limits — documents
- PUT replaces the payload in full; PATCH (0.26+) merges. PATCH patchable keys:
title,text,storeText,folderId,schemaId,userId,orgId,clientId,payload,expectedVersion.indexModeandexternalIdare immutable and rejected. - An update re-runs the indexing pipeline; old content is removed from the index as the new content is written.
getDocumentTextrequires the document to have been ingested withstoreText: true.- The presigned PUT must omit the Authorization header — the URL itself carries the grant.
Folders — client.folders.*
| Method | Purpose |
|---|---|
createFolder(body) | Create (optionally under a parent). |
getFolder({ id }) | Fetch by id. |
updateFolder({ id, body }) | PUT — name/description/ownership. |
patchFolder({ id, body }) | PATCH (RFC 7386). SDK 0.26+. |
deleteFolder({ id }) | Delete (rejects non-empty). |
listFolders({ userId?, orgId?, clientId?, startFrom?, limit? }) | List (FC-01 envelope). |
getFolderVersions({ id }) | Version history (FC-01 envelope). |
Create / update fields (FolderRequest)
| Field | Type | Notes |
|---|---|---|
name | string | Required. |
description | string | Optional. |
parentFolderId | string | Applied at create only; ignored on update. Omit to create under the context root. |
slug | string | Stable, sibling-unique slug; derived from the name when omitted. Lowercase letters/digits/hyphens. Immutable. |
userId / orgId / clientId | string | Ownership. |
expectedVersion | number | Optimistic concurrency. Ignored on create. |
FolderResponse (selected fields)
id, name, description, parentFolderId (null only for a true root),
slug, depth (0 at root), isProtected, userId, orgId, clientId, createdAt,
lastModified, version.
Notes & limits — folders
- No move / reparent.
parentFolderIdis fixed at creation; there is no operation to relocate a folder in the hierarchy. - Delete rejects a non-empty folder with a 400 — remove children first.
- The context root folder is protected (
isProtected: true) and created lazily on first folder interaction. Unparented folders are placed under it, so a folder created without a parent still has a non-nullparentFolderId(the root's id). - PATCH patchable keys:
name,description,userId,orgId,clientId,expectedVersion.slugandparentFolderIdare immutable and rejected.
Lookups & references
Lookup modes
Exactly one mode per call:
| Mode | Parameters | Constraints |
|---|---|---|
| exact | value | Any lookup field. Sensitive fields must use the body variant. |
| range | from + to | Both required. Inclusive, ascending. Non-sensitive fields only. |
| prefix | prefix | String, non-sensitive fields only. Ascending. |
Supplying zero or more than one mode is a 400. Range with only one bound is a 400. Prefix on a non-string field is a 400.
Unique vs non-unique (enumeration)
- A
uniquelookup field returns at most one record and is enforced unique on write. - A non-unique lookup field is an enumeration — it returns every record sharing the
value, paginated via the
{ data, nextCursor }envelope.
Sensitive-field lookup (body variant)
For a sensitive field, the exact value must not travel in a URL. The GET lookup rejects
value on a sensitive field and directs you to the body-based variant, where the value
travels in the request body and is blind-indexed server-side. Range and prefix are not
available on sensitive fields (a blind-indexed value has no usable order).
References
A reference field links to another record: it declares targetTypeName (required),
targetField (default externalId; must be a unique lookup on the target), cardinality
(one/many), and targetSurface. The platform can additionally maintain per-field
reverse-reference rows (opt-in) to index the inverse direction.
Notes & limits — lookups & references
- Partner-declared lookup fields are capped at 10 per schema (the three automatic ownership lookups do not count).
- The reverse-reference list endpoint is not yet available — you cannot query back-references through the API today.
- Reference targets are declarable now; write-time existence/type enforcement of a reference against its target is not yet active.
Version history — getRecordVersions / getDocumentVersions / getSchemaVersions / getFolderVersions
Each returns the FC-01 { data, nextCursor } envelope of immutable version rows for an
audited entity.
Version-row fields
| Field | Type | Notes |
|---|---|---|
id | string | Version-row id. |
changeType | enum | CREATE | UPDATE | DELETE. |
previousContent | string | JSON-stringified snapshot of the state prior to this change. Populated on UPDATE/DELETE; null on CREATE. JSON.parse to inspect. |
previousVersion | number | Version number before this change; null on CREATE. |
changeReason | string | Caller-supplied or system-derived reason. |
changedBy | string | Id of the user / key responsible. |
createdAt | string | ISO-8601 timestamp of the row. |
changedFields | object | Field-level diff: summary, changed field names, count, per-field old→new detail. Null on CREATE. |
Audit capability & retention
- Audit history is governed per schema by
capabilities.auditHistory(default true). Setting it false stops recording the change-history trail for that type's data; it never deletes or affects the records/documents themselves. Tombstones on delete are recorded regardless. - Version rows are written asynchronously (typically 1–3 seconds after a write returns) — poll briefly if you read history immediately after a write.
- Audit and version history are retained compliantly; heavy historical content is externalized to a write-once, retention-governed store, and the history forms a tamper-evident continuity chain. The full retention and integrity posture lives in ../operations-trust/compliance.md.
Errors
The platform returns a uniform error contract. Common cases for the data model:
| Status | Meaning (data-model context) |
|---|---|
400 | Validation error: schema-field violation, bad identifier, multiple/zero lookup modes, range/prefix on a sensitive field, prefix on a non-string field, delete of a non-empty folder, immutable field present in a PATCH, or a top-level field set to null in a PATCH. |
404 / "not found" | The entity does not exist, or belongs to another tenant/context, or is out of the caller's token scope — a single uniform shape (the message never distinguishes these). |
409 VERSION_CONFLICT | expectedVersion did not match — the entity changed since you read it; it is left untouched. |
501 not_implemented | A reserved-but-unbuilt operation (batch record write/lookup/get). |
Where to go next
- explanation.md — the concepts and the why.
- how-to.md — runnable guides for every operation above.
- ../operations-trust/compliance.md — version history retention, the tamper-evident chain, and sensitive-data handling.