Workspace API
Search Projects
Search the projects you have saved in your workspace with POST /workspace/projects/search.
POST https://api.parcelengineering.com/api/v1/workspace/projects/searchThis endpoint searches only the projects you have saved and annotated in your workspace (your book), not the global Parcel dataset. It does not accept view_id. For Dynamic or Static View execution over the broader Projects browse base, use POST /workspace/views/{id}/records/search. To find new projects to track, use the Data API projects search first, then upsert them into your workspace.
The Workspace API requires the Pro plan. A request from a non-Pro workspace or a non-member receives 403 forbidden.
Query parameters
| Parameter | Description |
|---|---|
workspace_id | Attribution. Required when authenticating with a user JWT (for example, via the MCP server). Optional for API keys. Omitting it on a user-token request returns 400 bad_request. |
Request body
All fields are optional. An empty body returns the first 25 projects sorted by updated_at descending.
| Field | Type | Default | Description |
|---|---|---|---|
query | string (min 1) | (none) | Full-text search term matched against project name. |
filters | object | (none) | Field, range, and relational filters. |
sort.field | string | updated_at | Sort field. Must be a valid sort key (see below). Required when sort is present. |
sort.order | asc | desc | desc | Sort direction. |
limit | integer 1..100 | 25 | Records per page. |
offset | integer 0..10000 | 0 | Zero-based record offset for pagination. |
search_after | string | (none) | Opaque keyset cursor from the previous response’s metadata.search_after. Pass it to fetch the next page. |
Sort keys
| Valid sort fields | Default |
|---|---|
updated_at, last_signal_at, name, created_at | updated_at (desc) |
Workspace filters
| Filter key | Type | Notes |
|---|---|---|
workspace_status | field | Your workflow status string. Exact match. |
tags | field | Tag value. Array value = OR. |
name | field | Project name. Supports fuzzy match. |
stage | field | Project stage value. Array value = OR. |
primary_use | field | Building use type. Array value = OR. |
city | field | City name. Fuzzy by default. |
state | field | State code, for example "MA". |
residential_units | range | Integer range, for example { "min": 10 }. |
gross_floor_area_sf | range | Numeric range in square feet. |
cost_of_construction_usd | range | Numeric range in US dollars. |
last_signal_at | range | ISO 8601 date range, for example { "gte": "2026-01-01" }. |
Relational filters
| Key | Inner filter fields |
|---|---|
has_account | account_type, name |
has_signal | signal_type, filed_at (range) |
has_contact | title, name |
Example
curl -X POST https://api.parcelengineering.com/api/v1/workspace/projects/search \ -H "Authorization: Bearer pcl_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "filters": { "stage": { "value": "under_construction" }, "state": { "value": "MA" } }, "sort": { "field": "last_signal_at", "order": "desc" }, "limit": 25 }'const response = await fetch( 'https://api.parcelengineering.com/api/v1/workspace/projects/search', { method: 'POST', headers: { 'Authorization': 'Bearer pcl_your_api_key', 'Content-Type': 'application/json', }, body: JSON.stringify({ filters: { stage: { value: 'under_construction' }, state: { value: 'MA' }, }, sort: { field: 'last_signal_at', order: 'desc' }, limit: 25, }), });
const { data, metadata } = await response.json();Response
{ "data": [ { "id": "7b2e4d1f-0001-4c8e-af6b-000000000001", "name": "100 Seaport Boulevard", "city": "Boston", "state": "MA", "stage": "under_construction", "primary_use": "mixed_use", "residential_units": 120, "gross_floor_area_sf": 180000, "cost_of_construction_usd": 42000000, "last_signal_at": "2026-06-01T00:00:00Z", "workspace_status": "watching", "notes": "GC bid due Q3", "tags": ["seaport", "mixed-use"] } ], "metadata": { "total": 11, "total_is_capped": false, "limit": 25, "offset": 0, "search_after": null, "credits": 11 }}The data array is trimmed to one record above. A page returning 11 projects costs 11 credits.
Metadata fields
| Field | Description |
|---|---|
total | Match count, capped at 1,000. When more than 1,000 projects match, total reports 1000 and total_is_capped is true. |
total_is_capped | true when the actual count exceeds the cap. |
limit | Page size, echoed back from the request. |
offset | Echoed back from the request, or 0 when paging with search_after. |
search_after | Opaque cursor for the next page, or null on the last page. |
credits | Credits consumed by this request. Equals the number of projects returned. |
Each project returned costs 1 credit toward your workspace’s rolling 24-hour ceiling of 250,000 credits. See Credits.