API documentation
The BuildVue API hands you the same permit backed development projects the web app shows, as JSON, so you can pull them into your own reporting, your CRM or a spreadsheet. It is part of the Business plan. Every endpoint returns visible development projects only, the same rule the product follows, so single family homes and other non development work never appear.
The base address is https://buildvue.co/api/v1 and every response is JSON. A call that works wraps its payload as { data, meta } and a call that fails returns { error }, so you can branch on the shape alone.
Authentication
Create a key on your API keys page. A key is shown once, at the moment you create it, because we keep only a fingerprint of it afterwards. Store it the way you store any other secret and keep it out of code you publish. You can hold five keys at a time and you can revoke any of them from the same page, which takes effect on the next request.
Send the key as a bearer token on every request.
curl https://buildvue.co/api/v1/projects \
-H "Authorization: Bearer bv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"A request with no key, or with a key that has been revoked, comes back as 401. A key belonging to an account on a smaller plan comes back as 403.
List projects
GET /api/v1/projects returns a page of projects with the filters, sorting and totals the web app uses. Every parameter is optional.
| Parameter | What it does |
|---|---|
| page | Page number, starting at 1. |
| pageSize | Projects per page. The default is 50 and the most you can ask for is 100. |
| sort | One of recency, lastActivity, status, value, stories, units, commercial, retail, parking. |
| sortDir | asc or desc. The default is desc. |
| text | Free text over addresses, permit numbers, descriptions, contractors, developers and architects. |
| city | City name, such as Seattle or Bellevue. |
| neighborhood | One neighborhood name. Use neighborhoods for a comma separated list. |
| type | residential, commercial or mixed_use. |
| subType | One sub type such as multi_family or retail. Use subTypes for a comma separated list. |
| status | design_review, land_use, construction or complete. A comma separated list works too. |
| zoning | One zoning code. Use zonings for a comma separated list. |
| applicationDate | last_month, last_quarter, last_year or gt_year. |
| north, south, east, west | Map bounds in degrees. Send all four together to filter by area. |
| valueMin, valueMax | Estimated construction value range in dollars. |
| storiesMin, storiesMax | Height range in stories. |
| unitsMin, unitsMax | Residential unit count range. |
| parkingMin, parkingMax | Parking stall count range. |
| includeOldCompleted | Set to true to include projects that finished long ago. They are left out by default. |
curl "https://buildvue.co/api/v1/projects?city=Seattle&status=construction&unitsMin=50&pageSize=2" \
-H "Authorization: Bearer $BUILDVUE_API_KEY"{
"data": [
{
"id": "clx8f0k2p0001qk3h9m2v7c1a",
"address": "1200 Stewart St",
"city": "Seattle",
"neighborhood": "Denny Triangle",
"status": "construction",
"projectType": "mixed_use",
"projectSubTypes": ["multi_family", "retail"],
"unitCount": 386,
"stories": 44,
"parkingSpaces": 120,
"estimatedValue": "184000000",
"latitude": 47.6183,
"longitude": -122.3361
}
],
"meta": {
"page": 1,
"limit": 2,
"total": 137,
"totalPages": 69,
"aggregates": { "count": 137, "units": 21044, "estValue": 8114000000 },
"version": "v1"
}
}The example above is trimmed. A record carries every field the app holds for a project, and anything the source records leave blank comes back as null rather than being dropped.
Get one project
GET /api/v1/projects/{id} returns the full record for one project, with its permits, parcels, sales history, contacts and press coverage. The id is the one the list endpoint gives you.
curl https://buildvue.co/api/v1/projects/clx8f0k2p0001qk3h9m2v7c1a \
-H "Authorization: Bearer $BUILDVUE_API_KEY"{
"data": {
"id": "clx8f0k2p0001qk3h9m2v7c1a",
"address": "1200 Stewart St",
"status": "construction",
"developer": "Onni Group",
"architect": "Weber Thompson",
"unitCount": 386,
"permits": [
{
"permitNumber": "6811234-CN",
"type": "construction",
"status": "issued",
"jurisdiction": "seattle",
"contractor": "Lease Crutcher Lewis",
"contractorLicense": "LEASECL881QK",
"applicationDate": "2024-03-11T00:00:00.000Z",
"issueDate": "2025-01-22T00:00:00.000Z"
}
],
"contacts": [
{ "name": "Onni Group", "role": "developer", "company": "Onni Group" }
],
"parcels": [
{ "pin": "0659000305", "sales": [{ "price": 42500000, "date": "2021-06-30T00:00:00.000Z" }] }
],
"newsArticles": []
},
"meta": { "version": "v1" }
}Pipeline aggregates
GET /api/v1/aggregates returns counts and sums for each phase of the pipeline, which is the quickest way to size a market without paging through every project. The filters work as they do on the project list.
| Parameter | What it does |
|---|---|
| text | Free text, matched the same way as on the project list. |
| type | residential, commercial or mixed_use. |
| zoning | One zoning code. Use zonings for a comma separated list. |
| north, south, east, west | Map bounds in degrees. Send all four together to filter by area. |
curl "https://buildvue.co/api/v1/aggregates?type=residential" \
-H "Authorization: Bearer $BUILDVUE_API_KEY"{
"data": {
"design_review": { "count": 62, "units": 9184, "parking": 2410, "officeSqft": 0, "retailSqft": 41200, "estValue": 3120000000 },
"land_use": { "count": 148, "units": 19022, "parking": 5104, "officeSqft": 122000, "retailSqft": 96400, "estValue": 6740000000 },
"construction": { "count": 137, "units": 21044, "parking": 6890, "officeSqft": 210500, "retailSqft": 118300, "estValue": 8114000000 },
"complete": { "count": 204, "units": 28110, "parking": 9033, "officeSqft": 318000, "retailSqft": 174900, "estValue": 10980000000 }
},
"meta": { "version": "v1" }
}Errors
Every failure uses one envelope, so you can read the code without parsing the message. The message is meant for a person reading a log and may be reworded. The code will not change.
{
"error": {
"code": "UPGRADE_REQUIRED",
"message": "The developer API is part of the Business plan. Upgrade to Business to use it."
}
}| Code | What it does |
|---|---|
| UNAUTHORIZED (401) | The key is missing, mistyped or revoked. |
| UPGRADE_REQUIRED (403) | The account behind the key is not on the Business plan. |
| INVALID_QUERY (400) | A query parameter failed validation. The details field names the fields at fault. |
| INVALID_ID (400) | The project id is not a well formed id. |
| NOT_FOUND (404) | No visible project carries that id. |
| RATE_LIMITED (429) | You went past your rate limit. Retry-After tells you how many seconds to wait. |
| INTERNAL_ERROR (500) | Something failed on our side. Retrying is safe. |
Rate limits
Each key may make 60 requests a minute. Calls for a single project also draw on an account wide budget of 600 an hour that is shared with the web app, so a busy afternoon inside the product counts toward it as well.
Going past a limit gives you a 429 carrying the RATE_LIMITED code. The response includes Retry-After in seconds, along with X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, so your client can back off without guessing.
Questions
Write to support@buildvue.co if you need a field the API does not return yet, or if you are planning something large enough that these limits get in your way.