Getting started
Create a free account, mint a key under Settings → API keys, and make your first successful call — including a metered one — in about five minutes.
How to get started
- 1Create a free account.
- 2After you sign in, open Settings → API keys.
- 3Click Create new secret key, copy it once, and store it safely.
- 4Your free trial includes 100 API credits (1 credit per record delivered). Trial credits do not reset monthly — they are a one-off evaluation budget.
- 5Send
Authorization: Bearer …tohttps://api.boardwalkai.com/api/v1.
The rest of this page walks those calls. The first three cost nothing, so you will know the key works and what your query costs before you spend a credit.
1. Get a key
Sign up for a free account, then mint a key under Settings → API keys. You do not need a paid subscription to create a key; entitlement is checked when you call, not when you mint. A free trial includes 100 credits for evaluation over the API.
The key you create there begins with bwk_live_ and reads the production corpus against your trial balance. That is the right credential for getting started. Keys prefixed bwk_test_ are reserved for a separate sandbox environment that is not serving data yet — do not use one for these first calls. Prefix detail and rotation: Authentication.
2. Prove the key works, for free
List the states you can filter by
curl 'https://api.boardwalkai.com/api/v1/locations/states' \
-H 'Authorization: Bearer bwk_live_YOUR_KEY'Response · HTTP 200
{
"data": [
{
"id": 54,
"name": "Arizona",
"abbreviation": "AZ",
"latitude": 34.0489,
"longitude": -111.0937,
"entitled": false
},
{
"id": 57,
"name": "Colorado",
"abbreviation": "CO",
"latitude": 39.5501,
"longitude": -105.7821,
"entitled": false
},
{
"id": 1,
"name": "Utah",
"abbreviation": "UT",
"latitude": 39.321,
"longitude": -111.0937,
"entitled": true
}
],
"meta": {
"geographyScope": "states",
"entitledStateIds": [
1
],
"countyRestricted": false
}
}The response shape on this page is the one the endpoint builds — the keys, their nesting and their types are asserted against the shipping code by a test. The numbers inside it are the scenario being walked through, not a measurement of the corpus.
A 200 here means your key is good. If you get 401, the credential did not reach us — check that the header is Authorization: Bearer … and that you copied the whole key.
3. Ask what your real query would cost
Narrow the query until it becomes affordable
curl 'https://api.boardwalkai.com/api/v1/projects/count?states=UT&assetClasses=Apartment%20Building&meetingDateFrom=2026-05-01&totalUnitCountMin=50' \
-H 'Authorization: Bearer bwk_live_YOUR_KEY'Response · HTTP 200
{
"data": {
"matchCount": 250,
"matchCountIsExact": true,
"matchCountBasis": "enumerated",
"countedAs": "distinct_projects",
"collapseApplied": true,
"duplicatesCollapsed": 0,
"scanCeiling": 10000,
"billable": {
"records": 250,
"credits": 250,
"creditRate": 1,
"isUpperBound": true,
"nonBillable": {
"alreadyDeliveredUnchanged": 0,
"ledgerApplied": true
}
},
"affordability": {
"affordable": true,
"blockReason": null,
"shortfallCredits": 0,
"maxAffordableRecords": 500,
"boundBy": "period_balance",
"unlimited": false
},
"ordering": {
"sort": "meetingDate",
"order": "desc",
"tiebreak": null,
"meaning": "Most recent meeting evidence first — the date of the meeting the record was extracted from, not when Boardwalk ingested it and not when the project was created."
},
"truncation": {
"policy": "refuse",
"wouldTruncate": false,
"deliverableRecords": null,
"explanation": "A metered request for this filter set fits inside the remaining balance, so it would deliver every matching record."
}
},
"meta": {
"schemaVersion": "2026-08-13",
"representation": "standard",
"deliveryMode": "all",
"credits": {
"limit": 500,
"used": 0,
"remaining": 500,
"charged": 0,
"periodStart": "2026-08-01",
"periodEnd": "2026-08-31",
"isTeamPool": true
},
"appliedFilters": {
"states": [
1
],
"assetClasses": [
"Apartment Building"
],
"meetingDateFrom": "2026-05-01T00:00:00+00:00",
"totalUnitCountMin": 50
},
"appliedDefaults": [],
"resolvedFrom": {
"states": [
{
"input": "UT",
"id": 1
}
]
},
"warnings": []
},
"links": {
"self": "https://api.boardwalkai.com/api/v1/projects/count?states=UT&assetClasses=Apartment%20Building&meetingDateFrom=2026-05-01&totalUnitCountMin=50",
"search": "https://api.boardwalkai.com/api/v1/projects/search?states=UT&assetClasses=Apartment%20Building&meetingDateFrom=2026-05-01&totalUnitCountMin=50",
"docs": "https://boardwalkai.com/docs/api/budgets/"
}
}The response shape on this page is the one the endpoint builds — the keys, their nesting and their types are asserted against the shipping code by a test. The numbers inside it are the scenario being walked through, not a measurement of the corpus.
This step is not a best practice, it is how the product works. On a paid plan, a request that costs more than your balance is refused, not truncated, so counting first is how you avoid a 402. A free-trial key instead delivers what its remaining balance covers and reports the cutoff in meta.trialTruncation. Read affordability.affordable and billable.credits before either call.
4. Make the metered call
Your first metered call
curl 'https://api.boardwalkai.com/api/v1/projects/search?states=UT&assetClasses=Apartment%20Building&meetingDateFrom=2026-05-01&totalUnitCountMin=50&limit=1' \
-H 'Authorization: Bearer bwk_live_YOUR_KEY'Response · HTTP 200
{
"data": [
{
"id": 184203,
"recordType": "project",
"projectName": "Alta Ridge Phase II",
"projectHeadline": "Planning Commission approved 240 apartments with conditions",
"boardwalkLink": "https://boardwalkai.com/map/#project=184203",
"mergedFrom": [
184203,
184987
],
"lastUpdated": "2026-06-18T09:22:41Z",
"meetingDate": "2026-06-17",
"delivery": {
"alreadyExported": false,
"updatedSinceExport": null,
"lastExportedAt": null,
"billed": true
},
"address": "3600 S Constitution Blvd, West Valley City, UT",
"city": "West Valley City",
"county": "Salt Lake",
"state": "UT",
"postalCode": "84119",
"latitude": 40.6916,
"longitude": -112.0011,
"locationPrecision": "address",
"locationPrecisionLabel": "Address",
"isApproximate": false,
"parcelApn": [
"15-27-301-004"
],
"propertyType": "residential",
"propertyTypeLabel": "Residential",
"propertySubtype": "multifamily",
"propertySubtypeLabel": "Multifamily",
"assetClass": "Apartment Building",
"assetClassLabel": "Apartment Building",
"landUses": [
{
"type": "residential",
"typeLabel": "Residential",
"subtype": "multifamily",
"subtypeLabel": "Multifamily",
"assetClass": "Apartment Building",
"assetClassLabel": "Apartment Building",
"matchedOn": []
}
],
"status": "approved_with_conditions",
"statusLabel": "Approved with Conditions",
"statusDetail": "The commission approved the preliminary plat subject to eight conditions.",
"requestType": "final_plat",
"requestTypeLabel": "Final Plat",
"decisionBody": "Planning Commission",
"caseNumbers": [
"PLAT-2026-0142"
],
"acreage": 9.8,
"squareFootage": null,
"unitCount": [
{
"count": 240,
"type": "apartment",
"typeLabel": "Apartment"
}
],
"totalUnitCount": 240,
"bedroomCount": null,
"buildingStories": null,
"floorCount": null,
"buildingHeightFeet": null,
"parkingSpaces": 372,
"existingZoning": "A-1",
"proposedZoning": "RM-16",
"isRezone": true,
"constructionType": "new_building",
"constructionTypeLabel": "New Building",
"ownerType": "private",
"ownerTypeLabel": "Private",
"constructionDescription": "A 240-unit garden-style apartment community on 9.8 acres.",
"developerCompany": "Alta Ridge Development LLC",
"developerCompanyRole": "developer",
"developerCompanyRoleLabel": "Developer",
"contacts": [
{
"name": "Rachel Okafor",
"title": "Director of Development",
"role": "developer",
"roleLabel": "Developer",
"partyClass": "external",
"partyClassLabel": "External Party",
"entityType": "person",
"company": "Alta Ridge Development LLC",
"email": "r.okafor@example.com",
"emailConfidence": "high",
"emailSource": "filing",
"phone": "+1-555-0142",
"phoneConfidence": "high",
"phoneSource": "filing",
"linkedinUrl": null,
"linkedinConfidence": null,
"linkedinSource": null,
"contactProvenance": "filing",
"enrichmentSource": null,
"enrichedAt": null,
"enrichmentStatus": "not_requested",
"contactsWithheldReason": null
}
],
"contactEnrichment": {
"status": "not_requested",
"statusLabel": "Not Requested",
"attemptedAt": null,
"contactsFound": 0,
"source": "registry"
},
"companyEnrichment": [],
"publicOfficials": [
{
"name": "Dana Whitfield",
"title": "Senior Planner",
"role": "city_planner",
"roleLabel": "City Planner",
"partyClass": "government",
"organization": "West Valley City"
}
],
"contactSummary": {
"externalCount": 1,
"governmentCount": 1,
"unclassifiedCount": 0,
"withEmail": 1,
"withPhone": 1,
"withLinkedin": 0,
"enrichedCount": 0,
"lowConfidenceWithheld": 0,
"withheldCount": 0,
"withheldReason": null
},
"keyFacts": [
{
"fact": "240 apartment units across six buildings",
"category": "unit_mix",
"categoryLabel": "Unit Mix"
}
],
"evidence": "Commissioner Reyes moved to approve subject to conditions 1-8.",
"voteSummary": {
"yes": 2,
"no": 1,
"abstain": 0,
"absent": 1,
"total": 4,
"isUnanimous": false,
"meetingDate": "2026-06-17"
}
}
],
"meta": {
"schemaVersion": "2026-08-13",
"representation": "standard",
"total": 1,
"pageCount": 1,
"hasMore": true,
"limit": 1,
"offset": 0,
"creditsUsed": 1,
"creditsRemaining": 299,
"trialTruncation": null,
"searchMethod": "redisearch",
"appliedFilters": {
"states": [
1
],
"assetClasses": [
"Apartment Building"
],
"meetingDateFrom": "2026-05-01T00:00:00+00:00",
"totalUnitCountMin": 50
},
"appliedDefaults": [],
"resolvedFrom": {
"states": [
{
"input": "UT",
"id": 1
}
]
},
"warnings": [],
"matchCount": null,
"matchCountIsExact": false,
"matchCountBasis": "not_computed",
"duplicatesCollapsed": 0,
"collapseApplied": true,
"delivery": {
"mode": "all",
"notPreviouslyExported": 1,
"previouslyExported": 0,
"updatedSinceExport": 0,
"billed": 1,
"notRebilled": 0,
"ledgerApplied": true
}
}
}Record bodies on this page were produced by running Boardwalk's production response mapper over a documented sample project, so the field set, the labels and the empty fields are exactly what the API emits. The project itself is a sample, not a real filing.
This call reuses the exact filter set from links.search in step 3 and adds only limit=1, so the quote and the purchase cannot silently describe different markets. One record, one credit. Two things to notice on your first response: meta.creditsRemaining has gone down by exactly one, and the record carries a delivery block. That block is why pulling this same record again tomorrow, if it has not changed, is free.
Rate limits before you loop
Paid keys are limited to 60 requests per minute. Watch X-RateLimit-Remaining and back off before you hit 429 — a well-behaved client rarely needs the error path. Full headers, Retry-After, and cookbook: Rate limits.
What you just spent
| Step | Endpoint | Credits |
|---|---|---|
| 1 | Minting a key | 0 |
| 2 | GET /locations/states | 0 |
| 3 | GET /projects/count | 0 |
| 4 | GET links.search with limit=1 | 1 |
| Total | 1 |
Where to go next
Ready to make a call?
A free Boardwalk trial includes API access and a sandbox key. Counting, taxonomy, location lookups and the analytics plane cost nothing, so you can evaluate the data before you spend a credit.