Skip to content

Workspace API

Signals

Manage workspace signal subscriptions, the Home queue, and triage state.

Signal endpoints cover two areas: the raw signal feed (/signals, /signals/{id}) and the workspace-specific queue, subscriptions, and triage system (/signals/queue, /signals/queue/stats, POST /signals/triage, and the /signal-subscriptions family).

All endpoints require a Bearer token and scope every query to a workspace via workspace_id.


GET /signals

List signals across all projects. Not city-limited by default; add ?city= to scope.

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope
project_iduuidFilter to one project
account_iduuidFilter to projects associated with this account
signal_typestringOne of the signal type values (see below)
filed_afterISO 8601 datetimeLower bound on filed_at (inclusive)
filed_beforeISO 8601 datetimeUpper bound on filed_at (exclusive)
discovered_afterISO 8601 datetimeLower bound on discovered_at (inclusive)
qstringFree-text fuzzy search on filing ID, source URL, project name
citystringOptional city filter
limitintegerMax results, default 50, max 200
offsetintegerPagination offset, default 0

Response 200

{
"signals": [
{
"id": "e3b0c442-98fc-1c14-9afb-f0e1e5c7b7d3",
"project_id": "7f3c1a42-2b8d-4e9f-a1c5-0d6b2e3f4a5b",
"project_name": "125 Summer Street",
"project_primary_address": "125 Summer St, Boston, MA 02110",
"signal_type": "permit_issued",
"filed_at": "2024-03-15T00:00:00.000Z",
"discovered_at": "2024-03-16T08:22:11.000Z",
"source_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source_slug": "boston-isd",
"source_display_name": "Boston Inspectional Services",
"source_base_url": "https://www.boston.gov/departments/inspectional-services",
"source_logo_domain": "boston.gov",
"source_filing_id": "ALT-2024-001234",
"source_url": "https://aca.boston.gov/",
"reported_cost_usd": 1500000,
"reported_gross_floor_area_sf": 8400
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": null
}
}

GET /signals/{id}

Get a single signal including raw_data (the original source payload).

Path parameters

ParameterTypeDescription
iduuid (required)Signal ID

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope

Response 200

{
"signal": {
"id": "e3b0c442-98fc-1c14-9afb-f0e1e5c7b7d3",
"project_id": "7f3c1a42-2b8d-4e9f-a1c5-0d6b2e3f4a5b",
"project_name": "125 Summer Street",
"project_primary_address": "125 Summer St, Boston, MA 02110",
"signal_type": "permit_issued",
"filed_at": "2024-03-15T00:00:00.000Z",
"discovered_at": "2024-03-16T08:22:11.000Z",
"source_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source_slug": "boston-isd",
"source_display_name": "Boston Inspectional Services",
"source_base_url": "https://www.boston.gov/departments/inspectional-services",
"source_logo_domain": "boston.gov",
"source_filing_id": "ALT-2024-001234",
"source_url": "https://aca.boston.gov/",
"reported_cost_usd": 1500000,
"reported_gross_floor_area_sf": 8400,
"raw_data": {}
}
}

Signal type values

project_announcement · pre_application · site_acquisition · demolition_permit · site_prep · entitlement_application · environmental_review · public_review · entitlement_approval · entitlement_denial · withdrawal · expiration · permit_filed · permit_issued · construction_loan · team_update · completion


GET /signals/queue

The Home triage queue. Returns signals of subscribed types, discovered after each subscription’s queue watermark and filed within the 90-day history window. Ranked new-first, then by subscription priority (high → medium → low), then by filed_at descending. Each row carries its triage state and derived priority. pagination.total is the filtered count.

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope
statusstring (repeatable)new or done; omit for both
signal_typestring (repeatable)Filter to one or more signal types
prioritystring (repeatable)high, medium, or low
citystringOptional city filter
qstringFree-text fuzzy search
limitintegerMax results, default 50, max 200
offsetintegerPagination offset, default 0

Response 200QueueSignal objects extend SignalSummary with triage fields:

{
"signals": [
{
"id": "e3b0c442-98fc-1c14-9afb-f0e1e5c7b7d3",
"project_id": "7f3c1a42-2b8d-4e9f-a1c5-0d6b2e3f4a5b",
"project_name": "125 Summer Street",
"project_primary_address": "125 Summer St, Boston, MA 02110",
"signal_type": "permit_issued",
"filed_at": "2024-03-15T00:00:00.000Z",
"discovered_at": "2024-03-16T08:22:11.000Z",
"source_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source_slug": "boston-isd",
"source_display_name": "Boston Inspectional Services",
"source_base_url": "https://www.boston.gov/departments/inspectional-services",
"source_logo_domain": "boston.gov",
"source_filing_id": "ALT-2024-001234",
"source_url": "https://aca.boston.gov/",
"reported_cost_usd": 1500000,
"reported_gross_floor_area_sf": 8400,
"triage_status": "new",
"priority": "high",
"triaged_by": null,
"triaged_at": null
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 12
}
}

GET /signals/queue/stats

Lightweight counts over the same queue rule as GET /signals/queue. Powers the Home header, tab/chip counts, the Settings Signals count column, and the sidebar badge. Poll this endpoint — it is cheap.

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope

Response 200

{
"new_count": 12,
"high_priority_new_count": 4,
"done_count": 31,
"type_counts": [
{ "signal_type": "permit_issued", "new_count": 7 },
{ "signal_type": "construction_loan", "new_count": 5 }
]
}

POST /signals/triage

Bulk-mark signals done or new in the workspace-shared queue. Pass up to 100 signal IDs per call. status "done" records who acted and removes signals from the New tab for the whole workspace; status "new" restores them. Idempotent.

Request body

{
"workspace_id": "uuid",
"signal_ids": ["uuid", "uuid"],
"status": "done"
}
FieldTypeDescription
workspace_iduuid (required)Workspace scope
signal_idsuuid[] (required)1–100 signal IDs
statusstring (required)done or new

Response 200

{ "updated": 2 }

GET /signal-subscriptions

List all signal type subscriptions for the workspace. Each subscription includes its priority, alert channels, recipients, and a live count of untriaged new signals currently in the Home queue for that type.

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope

Response 200

{
"subscriptions": [
{
"signal_type": "permit_issued",
"priority": "high",
"channels": ["email"],
"notify_all_members": false,
"recipient_user_ids": ["uuid"],
"new_count": 7,
"created_at": "2024-03-01T12:00:00.000Z",
"updated_at": "2024-03-01T12:00:00.000Z"
}
]
}

SubscriptionResource fields

FieldTypeDescription
signal_typestringOne of the signal type values
prioritystringhigh, medium, or low
channelsstring[]Alert delivery channels; currently email only (teams, slack coming soon)
notify_all_membersbooleanWhen true, emails all workspace members (including future members); takes precedence over recipient_user_ids
recipient_user_idsuuid[]Explicit email recipients (must be workspace members; re-validated at send time)
new_countintegerLive count of untriaged signals of this type in the queue
created_atISO 8601Subscription creation time
updated_atISO 8601Last modification time

PUT /signal-subscriptions/{signal_type}

Subscribe to a signal type or update an existing subscription. Idempotent upsert keyed by signal_type. Creating a subscription starts queueing signals discovered from now (with a 14-day lookback so the queue is not empty on first use). Updates apply only the provided fields and never reset the queue watermark.

Path parameters

ParameterTypeDescription
signal_typestring (required)One of the signal type values

Request body

{
"workspace_id": "uuid",
"priority": "high",
"channels": ["email"],
"notify_all_members": false,
"recipient_user_ids": ["uuid"]
}
FieldTypeDescription
workspace_iduuid (required)Workspace scope
prioritystringhigh, medium, or low (default medium on create)
channelsstring[]Alert delivery channels; email is the only deliverable channel today
notify_all_membersbooleanEmail all workspace members
recipient_user_idsuuid[]Up to 100 explicit recipient user IDs; must be workspace members

Response 200 — returns the full subscription list after the upsert (same shape as GET /signal-subscriptions).


DELETE /signal-subscriptions/{signal_type}

Unsubscribe from a signal type. Signals of this type leave the Home queue immediately and no further alerts are sent. Re-subscribing later starts a fresh queue watermark.

Path parameters

ParameterTypeDescription
signal_typestring (required)One of the signal type values

Query parameters

ParameterTypeDescription
workspace_iduuid (required)Workspace scope

Response 200 — returns remaining subscriptions (same shape as GET /signal-subscriptions).

Response 404{ "error": { "code": "not_found", "message": "Not subscribed" } }


POST /signal-subscriptions/bulk

Transactional upsert of several subscriptions at once. Used by workspace onboarding. Created subscriptions get default settings (no email channel, medium priority) and a fresh 14-day lookback queue watermark. Existing subscriptions update only their priority; channels and recipients are never touched by this endpoint (use the single PUT for those). Types not listed are left untouched.

Request body

{
"workspace_id": "uuid",
"subscriptions": [
{ "signal_type": "permit_issued", "priority": "high" },
{ "signal_type": "construction_loan", "priority": "medium" }
]
}
FieldTypeDescription
workspace_iduuid (required)Workspace scope
subscriptionsarray (required)1–14 entries (one per unique signal type); each has signal_type (required) and priority (default medium)

Response 200 — returns the full subscription list after the upsert.