Workspace API
Workspace Views
Shared Dynamic and Static Views over Accounts, Contacts, and Projects — definition grammar, Favorites, and follow semantics.
A View is a named, workspace-shared scope over exactly one dataset (account, contact, or project). Dataset and type are immutable after creation. Names are trimmed, non-empty, and case-insensitively unique within a workspace and dataset.
| Type | Membership |
|---|---|
| Dynamic | Live query. Stores versioned web filter state (q plus dataset-specific fields). Membership is re-evaluated against current data on every open or search. |
| Static | Explicit set of record IDs in workspace_view_records. Membership changes only through add/remove. |
Definitions and Static membership are shared and editable by every workspace member. Favorites are personal: each member may favorite either type, order their Favorites, and use the resulting sidebar section. Favorites require a user-authenticated session (JWT); API keys cannot manage them.
In this API, follow means putting a record in a Static View (and, when useful, favoriting that View). It does not mean notifications, alerts, or activity subscriptions.
API keys may create, update, delete, and change membership on shared Views. Personal Favorite routes reject API keys with 400 user_identity_required.
Contact visibility and Static follow
Ordinary POST /workspace/contacts/search remains book-only (workspace_contacts). Static Contact membership is an additional visibility source for web Contacts browse, Contact detail, and View execution: a Contact stays visible after its last project link or book overlay disappears until the last same-workspace Static Contact membership is removed. Adding the first membership still requires the Contact to already be visible; a candidate row cannot bootstrap access.
Removing a record from its last Static View does not delete an existing workspace overlay. Deleting an overlay does not remove Static membership.
Definition grammar is not SearchRequest
Dynamic definitions use the web table FilterState contract (version, q, fields), not the nested Workspace/Data API SearchRequest shape (query, filters, relations). Sending a SearchRequest-style body as definition returns 400 invalid_view_definition. It is not translated or partially accepted.
Valid Account Dynamic definition:
{ "version": 1, "q": "architect", "fields": { "account_type": ["architect"], "icp_tier": ["tier_1"], "atlas_score": { "min": "60" } }}Invalid — nested SearchRequest (rejected):
{ "query": "architect", "filters": { "account_type": { "value": "architect" }, "icp_tier": { "value": "tier_1" } }}Static definitions are only:
{ "version": 1 }Membership lives in the records table, not in the definition.
v1 stored fields keys
| Dataset | Stored fields keys |
|---|---|
| Account | account_type, city, atlas_score, icp_tier, last_activity |
| Contact | role, status, account_id, city |
| Project | stage, primary_use, city, sqft, units, detected |
Project disposition is absent in v1: the web Projects table does not expose it, so stored View state cannot include a criterion the UI cannot show or edit.
Value shapes:
- Enum and dynamic-enum fields: non-empty arrays of unique strings (OR within one field).
- Entity fields (
account_id): one-element UUID string arrays. - Number ranges (
atlas_score,sqft,units): optional digit-stringmin/max. - Date ranges (
last_activity,detected): optionalYYYY-MM-DDafter/before. qis trimmed and ANDed with fields; different fields are ANDed.
Unknown fields, invalid enums, empty or duplicate values, malformed ranges, exact_match, exclude, and relational objects are rejected with invalid_view_definition.
Presentation
Both types may store versioned presentation:
{ "version": 1, "sorting": [], "column_visibility": {}}sorting uses TanStack { id, desc } column IDs. Presentation is web UI state. Public and MCP View-record searches ignore presentation sorting and use an explicit request sort or the dataset executor default.
Scopes and credits
| Surface | Auth | Credits |
|---|---|---|
| List / get Views | workspace:read (API key or member JWT) | 0 |
| Upsert / delete Views, add/remove membership | workspace:write | 0 |
| Favorites | User JWT + membership only | 0 |
POST /workspace/views/{id}/records/search | Same as other Workspace searches | 1 per returned row |
Related endpoints
- List Views
- Search View Records
- Ordinary book searches remain separate: Search Accounts, Search Contacts, Search Projects