Workspace API
Manage Views
List, fetch, create, update, and delete shared workspace Views with GET/POST/DELETE /workspace/views.
Every route below costs 0 credits. List and Get require workspace:read; Upsert and Delete require workspace:write. Pass workspace_id as a query parameter when authenticating with a user JWT; API keys infer it.
The Workspace API requires the Pro plan. A request from a non-Pro workspace or a non-member receives 403 forbidden.
See Workspace Views for the Dynamic/Static definition grammar and presentation contract.
List Views
GET https://api.parcelengineering.com/api/v1/workspace/viewsReturns shared View definitions and metadata for the workspace. Filter by id, name substring, dataset, type, or (with a user JWT) Favorites only.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workspace_id | string (UUID) | Conditional | Attribution. Required for user JWT; optional for API keys. |
id | string (UUID) | No | Fetch one View by id. |
query | string (min 1) | No | Case-insensitive name substring. |
dataset | account | contact | project | No | Limit to one dataset. |
view_type | dynamic | static | No | Limit to Dynamic or Static. |
favorite_only | true | false | No | Only the current user’s Favorites. Requires a user JWT; API keys receive 400 user_identity_required. |
limit | integer 1..100 | No | Default 25. |
offset | integer ≥ 0 | No | Default 0. |
Example
curl "https://api.parcelengineering.com/api/v1/workspace/views?dataset=account&view_type=dynamic" \ -H "Authorization: Bearer pcl_your_api_key"const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/views?dataset=account&view_type=dynamic', { headers: { 'Authorization': 'Bearer pcl_your_api_key' }, });
const { data, metadata } = await response.json();Response
{ "data": { "views": [ { "id": "a1b2c3d4-0001-4e8d-bf6a-000000000001", "workspace_id": "w1e2f3a4-0001-4b7c-9e5d-000000000001", "dataset": "account", "view_type": "dynamic", "name": "Tier 1 architects", "definition": { "version": 1, "q": "architect", "fields": { "account_type": ["architect"], "icp_tier": ["tier_1"] } }, "presentation": { "version": 1, "sorting": [], "column_visibility": {} }, "revision": 1, "created_by": null, "updated_by": null, "created_at": "2026-07-01T12:00:00.000Z", "updated_at": "2026-07-01T12:00:00.000Z", "is_favorite": false, "favorite_position": null } ] }, "metadata": { "limit": 25, "offset": 0, "credits": 0 }}Every listed View includes is_favorite and favorite_position. API-key principals always receive is_favorite: false and favorite_position: null (they have no user identity). User JWTs reflect the caller’s Favorites. Only Static Views include record_count (exact membership size after the entity join). Dynamic Views omit record_count; use View Records for a request-scoped total.
Get a View
GET https://api.parcelengineering.com/api/v1/workspace/views/{id}Returns one shared View definition and metadata. Unknown or out-of-workspace ids return 404 view_not_found.
Path parameters
| Parameter | Description |
|---|---|
id | UUID of the View. |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workspace_id | string (UUID) | Conditional | Attribution. Required for user JWT; optional for API keys. |
Example
curl https://api.parcelengineering.com/api/v1/workspace/views/a1b2c3d4-0001-4e8d-bf6a-000000000001 \ -H "Authorization: Bearer pcl_your_api_key"const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/views/a1b2c3d4-0001-4e8d-bf6a-000000000001', { headers: { 'Authorization': 'Bearer pcl_your_api_key' }, });
const { data, metadata } = await response.json();Response
{ "data": { "view": { "id": "a1b2c3d4-0001-4e8d-bf6a-000000000001", "workspace_id": "w1e2f3a4-0001-4b7c-9e5d-000000000001", "dataset": "account", "view_type": "static", "name": "Architects to follow", "definition": { "version": 1 }, "presentation": { "version": 1, "sorting": [], "column_visibility": {} }, "revision": 2, "created_by": "d1e2f3a4-0001-4b7c-9e5d-000000000001", "updated_by": "d1e2f3a4-0001-4b7c-9e5d-000000000001", "created_at": "2026-07-01T12:00:00.000Z", "updated_at": "2026-07-02T09:00:00.000Z", "record_count": 8 } }, "metadata": { "credits": 0 }}Upsert View
POST https://api.parcelengineering.com/api/v1/workspace/views/upsertPOST https://api.parcelengineering.com/api/v1/workspace/views/upsert/batchCreates a new shared View or updates an existing one. dataset and view_type are immutable after create. Dynamic definitions use the web filter FilterState grammar — not SearchRequest.
Create body
Provide name, dataset, view_type, and definition. Optional presentation. For a Static single create only, optional initial_record_ids (1–100 UUIDs) seeds membership in the same transaction:
- Zero valid IDs: nothing is created (
400 no_valid_records). - One or more valid IDs: the View and valid memberships are created together; invalid IDs appear in per-item
results.
initial_record_ids is not accepted on /upsert/batch. To seed more than 100 records, create with the first 100 and call View Records.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Trimmed, non-empty; case-insensitively unique per workspace + dataset. |
dataset | account | contact | project | Yes | Immutable. |
view_type | dynamic | static | Yes | Immutable. |
definition | object | Yes | Dynamic: { version: 1, q, fields }. Static: { version: 1 }. |
presentation | object | No | TanStack sorting / column visibility. |
initial_record_ids | string[] (UUID) | No | Static single create only. Max 100. |
Update body
| Field | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Existing View. |
expected_revision | integer ≥ 1 | Yes | Optimistic concurrency. Mismatch → 409 view_conflict. |
name | string | No | Rename. |
definition | object | No | Must match the View’s type/dataset. |
presentation | object | No | Replace presentation. |
Sending dataset or view_type on update is rejected.
Batch
POST /workspace/views/upsert/batch takes { "inputs": [ ... ] } with 1–100 create or update items (no initial_record_ids). Results are ordered; one failure never aborts the rest. See Batch Writes.
Example
curl -X POST https://api.parcelengineering.com/api/v1/workspace/views/upsert \ -H "Authorization: Bearer pcl_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Tier 1 architects", "dataset": "account", "view_type": "dynamic", "definition": { "version": 1, "q": "architect", "fields": { "account_type": ["architect"], "icp_tier": ["tier_1"], "atlas_score": { "min": "60" } } } }'const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/views/upsert', { method: 'POST', headers: { 'Authorization': 'Bearer pcl_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'Tier 1 architects', dataset: 'account', view_type: 'dynamic', definition: { version: 1, q: 'architect', fields: { account_type: ['architect'], icp_tier: ['tier_1'], atlas_score: { min: '60' }, }, }, }), });
const { data, metadata } = await response.json();Response
{ "data": { "view": { "id": "a1b2c3d4-0001-4e8d-bf6a-000000000001", "workspace_id": "w1e2f3a4-0001-4b7c-9e5d-000000000001", "dataset": "account", "view_type": "dynamic", "name": "Tier 1 architects", "definition": { "version": 1, "q": "architect", "fields": { "account_type": ["architect"], "icp_tier": ["tier_1"], "atlas_score": { "min": "60" } } }, "presentation": { "version": 1, "sorting": [], "column_visibility": {} }, "revision": 1, "created_by": null, "updated_by": null, "created_at": "2026-07-01T12:00:00.000Z", "updated_at": "2026-07-01T12:00:00.000Z" } }, "metadata": { "credits": 0 }}Static create with initial_record_ids also returns data.results (per-ID membership outcomes) and metadata.succeeded / metadata.failed.
Upsert errors
| Code | Status | When |
|---|---|---|
invalid_view_definition | 400 | Bad definition (including nested SearchRequest). |
view_name_conflict | 409 | Case-insensitive name already used for that dataset. |
view_conflict | 409 | expected_revision mismatch. |
view_not_found | 404 | Update target missing. |
no_valid_records | 400 | Static seed had zero valid IDs. |
Delete a View
DELETE https://api.parcelengineering.com/api/v1/workspace/views/{id}POST https://api.parcelengineering.com/api/v1/workspace/views/delete/batchDeletes a shared View. Favorites for every member cascade with the View. Static membership rows are removed.
Path parameters (single)
| Parameter | Description |
|---|---|
id | UUID of the View to delete. |
Batch body
{ "ids": ["a1b2c3d4-0001-4e8d-bf6a-000000000001", "b2c3d4e5-0002-4e8d-bf6a-000000000002"] }1–100 UUIDs. Per-item results in input order; one failure never aborts the rest. See Batch Writes.
Example
curl -X DELETE \ https://api.parcelengineering.com/api/v1/workspace/views/a1b2c3d4-0001-4e8d-bf6a-000000000001 \ -H "Authorization: Bearer pcl_your_api_key"const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/views/a1b2c3d4-0001-4e8d-bf6a-000000000001', { method: 'DELETE', headers: { 'Authorization': 'Bearer pcl_your_api_key' }, });
const { data, metadata } = await response.json();Response
{ "data": { "deleted": true }, "metadata": { "credits": 0 }}Unknown or out-of-workspace ids return 404 view_not_found on the single route. Batch items report per-id errors.