{
    "openapi": "3.0.3",
    "info": {
        "title": "Boardwalk Land Use Intelligence API",
        "version": "2026-08-18",
        "description": "Programmatic access to Boardwalk's land use project database — hundreds of thousands of\ndevelopment projects, zoning decisions, and building permits extracted from city and\ncounty meeting minutes across the United States.\n\n## Authentication\n\nAll endpoints require an API key as a bearer token:\n\n```\nAuthorization: Bearer bwk_live_...\n```\n\nCreate and rotate keys under **Settings → API keys**\n(https://boardwalkai.com/profile/api). Keys created there begin with `bwk_live_`\nand read the production corpus against your plan or free-trial credit balance.\n`bwk_test_` is reserved for a separate sandbox environment that is not serving\ndata yet — do not use a test-prefix key for evaluation. Keys issued before the\nBoardwalk rename begin with `csk_` and keep working indefinitely — there is\nnothing you need to do.\n\nKeys are held by a team and attributed to the person who created them, so a key\nkeeps working when its creator leaves, and a team owner can see and stop every\nkey that can spend the team's credits.\n\nYou may hold several named keys at once, and you can rotate one with a **24-hour\noverlap**: the replacement is issued immediately and the previous key keeps\nworking for the grace window, so you can deploy at your own pace. While a key is\nin that window its responses carry `X-Boardwalk-Key-Rotating: true` and a\n`Warning` header naming the moment it stops.\n\nA key is backed either by an active paid subscription (State, Multi-State, or\nNational plan) or by a free trial, which doubles as a metered evaluation sandbox —\nsee **Free trial** below.\n\n## Credits\n\nThe planning and reference surfaces — count, taxonomy, locations, account,\nanalytics, and alert configuration — are free. This is the complete billable\nroute list, generated from the same route and cost registry as the detailed docs:\n\n| Endpoint | Cost |\n| --- | --- |\n| `GET /projects/search` | **1 credit per record delivered.** JSON pages: charged for records actually delivered after collapse, with unchanged re-delivery free. Zero results cost nothing. `format=csv` does not use this search charge — it reserves product export credits (1 per core CSV row) and returns HTTP 202 with poll/download URLs. |\n| `GET /projects/{id}` | **1 credit per record delivered.** One credit when the record is new to you or changed since your last delivery; an unchanged re-read is free, just like the same record inside a search page. |\n| `GET /projects/sync` | **1 credit per record delivered.** Only records that are new to you, or that changed since you last received them, are billable. A sync page that returns nothing but unchanged records is free. |\n| `POST /projects/ai-search` | **1 credit per record delivered.** The same rate as a structured search. You pay for confirmed matches that are new to you or changed since their last delivery; rejected candidates and unchanged re-deliveries are free. |\n| `POST /projects/ai-search/jobs` | **1 credit per record delivered.** Credits are reserved up front against the requested limit and settled down to confirmed records that are new to you or changed since their last delivery. Unused reservation, including unchanged re-deliveries, is refunded. |\n| `GET /documents/{id}` | **1 credit per record delivered.** One source document, one credit. |\n| `GET /alerts/{alertId}/matches` | **1 credit per record delivered.** Records already delivered and unchanged since a scheduled run are re-readable here without a second charge; anything new or changed bills once. |\n| `POST /alerts/{alertId}/run` | **1 credit per record delivered.** A manual run is a real delivery: records new to you or changed since their last delivery bill at the standard rate. Runs are capped per alert per day. |\n| `GET /lists/{listId}/results` | **1 credit per record delivered.** Charged when you read, at the search rate — a list has no run that already billed its records, so this is a delivery, not a re-read. A record your account already holds unchanged is free (the same rule as search). Filter and polygon lists return their stored criteria plus a search link instead of records, free. |\n\nThe billable unit is the delivered record, on every plan and on the free trial\nalike. Paid credits reset on the 1st of each month and do not roll over. Check\nyour remaining balance with `GET /account/credits` or read the\n`X-Credits-Remaining` response header on any billed call.\n\n## Running out of credits\n\n**On a paid plan a request is never partially delivered.** If a request would\ndeliver more records than your balance can cover, it is refused with `402\ninsufficient_credits` and **nothing is returned and nothing is charged**. The\nerror body carries a quote — `details.quote.creditsRequired`,\n`creditsRemaining`, and `affordableRecordCount` — so you can narrow the request\nand retry. A short page therefore always means \"that is all that matched\", never\n\"that is all you could afford\".\n\n## Free trial\n\nA free trial includes **100 record credits in total** — the same unit paid plans\nare billed in, not 100 calls — and they are never refilled. Create a free\naccount, mint a key under Settings → API keys, and spend those credits with a\n`bwk_live_` key. Access is also limited to the geography the trial grants on the map.\n\nThe trial is the **one** exception to the rule above. Because a first realistic\nquery can match far more records than a 100-credit trial holds, a trial request\nthat runs past the remaining balance is **truncated rather than refused**: the\nrecords the balance covers are delivered with `200`, and `meta.trialTruncation`\nis populated with `reason: \"trial_credit_balance_reached\"`, the delivered and\nrequested counts, and the credits remaining. On a paid plan `meta.trialTruncation`\nis always `null`. Once a trial balance reaches zero, further billable requests\nreturn `402 credits_exhausted`.\n\n## Rate limits\n\nRequests are limited **per API key**, over a trailing 60 seconds: **60 requests per\nminute on any paid plan** and **10 per minute on a free-trial key**. Every response\ncarries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`;\na `429` also carries `Retry-After`. Before authentication, a missing credential on\nan authenticated route is limited at the trial rate per source IP; an unknown or unusable Boardwalk-shaped credential\nis limited at the trial rate per credential digest.\n\n## Representations\n\n`?representation=` selects how much of each record you receive:\n\n| Value | Fields | Use it for |\n| --- | --- | --- |\n| `compact` | 23 | agents and list views; small enough to hold a hundred records in a prompt |\n| `standard` (default) | 68 | the calibrated field set, matching the CSV export |\n| `full` | 89 | adds decisions with named votes, document metadata and `rawText` |\n\nEach representation nests inside the next, and **all three cost the same 1 credit per record** — you are billed for the record, not for the bytes. An unrecognised value returns `400`; it is never silently coerced to the default.\n\n## Why a field can be null\n\nEvery value Boardwalk returns is produced by our current-generation extraction.\nWhere current-generation extraction has not covered an attribute for a project,\nwe return `null` rather than an older, less accurate value.\n\nFilters currently match against our full historical index. A filter on one of\nthese attributes may therefore return a project whose evidence for that\nattribute predates our current extraction — in that case the corresponding field\nin the response is `null`. **Filtering the returned records on a non-null value\ngives you an exactly-current-generation result set.**\n\nThe most recently added projects are the most likely to have null measurements —\nacreage, unit counts, stories, parking and the rest of the measurement group —\nbecause measurement extraction lags ingest. A project's classification and\nidentity are complete regardless. Size an integration against this rather than\nagainst a full record.\n\n## Geographic filters\n\nStructured search, count and sync filters use the canonical names `states`,\n`counties` and `cities`. They accept numeric IDs or human-readable values: `states=UT`,\n`counties=Utah County`, and `cities=Provo` are all valid. Names are resolved\ncase-insensitively; an ambiguous place is refused rather than silently widened.\nThe older singular and `*Ids` spellings remain accepted aliases.\n\n## Geographic restrictions\n\nState and Multi-State plans can only return projects in the subscriber's\nlicensed states. Requesting a state outside your subscription returns\n`403 geographic_access_denied`. With no state filter, results are\nautomatically scoped to your licensed states.",
        "contact": {
            "name": "Boardwalk Support",
            "email": "support@boardwalkai.com",
            "url": "https://boardwalkai.com"
        }
    },
    "servers": [
        {
            "url": "https://api.boardwalkai.com/api/v1",
            "description": "Production"
        },
        {
            "url": "http://localhost:8000/api/v1",
            "description": "Local development"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "Projects",
            "description": "Search and retrieve land use development projects."
        },
        {
            "name": "Documents",
            "description": "Fetch the source meeting documents projects were extracted from."
        },
        {
            "name": "Taxonomy",
            "description": "Land use type, subtype, asset class, and action classification taxonomy."
        },
        {
            "name": "Locations",
            "description": "States, counties, and cities. IDs from here are used as filter values in project search."
        },
        {
            "name": "Reference",
            "description": "Filter value catalogues (statuses, owner types) used by search."
        },
        {
            "name": "Exports",
            "description": "CSV export jobs queued from the product or from search format=csv."
        },
        {
            "name": "Account",
            "description": "Plan, credit balance, and rate-limit info for the authenticated key."
        },
        {
            "name": "Analytics",
            "description": "Free counts, distributions and rankings. Returns aggregates and never record identity, so an analytical question costs nothing and only the records behind the answer are billed."
        }
    ],
    "paths": {
        "/projects/search": {
            "get": {
                "tags": [
                    "Projects"
                ],
                "summary": "Search projects with structured filters",
                "description": "Returns land use projects matching the given filters. Backed by a RediSearch index for fast filtering.\n\n**Cost: 1 credit per returned project that is new to your credit pool or has changed since delivery.** Unchanged re-deliveries are returned for free. If 100 net-new projects come back, you spend 100 credits; the exact charge is returned in `meta.creditsUsed`.\n\n**Geography:** `states`, `counties` and `cities` accept IDs or names (`states=UT`, `counties=Utah County`, `cities=Provo`). The older singular and `*Ids` spellings remain accepted aliases.\n\nList-valued filters accept a JSON array, a comma-separated value, or a repeated query parameter, e.g. `states=UT,CO` or `assetClasses=[\"Apartment Building\",\"Townhome\"]`.",
                "parameters": [
                    {
                        "name": "states",
                        "in": "query",
                        "required": false,
                        "description": "States, as numeric ids, USPS abbreviations (\"UT\") or full names (\"Utah\"). A list is an OR: pass every state you want. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `state`, `stateId`, `stateIds`. Accepted values: `/api/v1/locations/states`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "counties",
                        "in": "query",
                        "required": false,
                        "description": "Counties, as numeric ids or names (a trailing \"County\" is optional). A name is resolved against a single `states` value when one is given. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `county`, `countyId`, `countyIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "cities",
                        "in": "query",
                        "required": false,
                        "description": "Cities, as numeric ids or names. A name is resolved against a single `states`/`counties` value when one is given; an ambiguous name is an error, never a silently wider search. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `city`, `cityId`, `cityIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties/{countyId}/cities`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "bbox",
                        "in": "query",
                        "required": false,
                        "description": "Rectangle {north, south, east, west}. Records are returned only when their coordinates fall inside the rectangle — the engine prefilters with a circle and the corners of that circle are then removed. Accepted aliases: `bounds`. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "circle",
                        "in": "query",
                        "required": false,
                        "description": "Radius search {lat, lng, radiusMeters}. radiusMeters is 100–500000. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "polygon",
                        "in": "query",
                        "required": false,
                        "description": "GeoJSON linear ring [[lng, lat], …], 4–1000 vertices, first vertex equal to last. The engine prefilters with the ring's bounding circle and exact point-in-polygon runs afterwards. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertyTypes",
                        "in": "query",
                        "required": false,
                        "description": "Top-level land-use classification, e.g. \"Residential\". Case-insensitive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `type`, `types`, `propertyType`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classification. Also accepts \"Type - Subtype\" compounds, which are split server-side. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `subtype`, `subtypes`, `propertySubtype`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "assetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classification, e.g. \"Apartment Building\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `assetClass`, `assetClasses[]`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludePropertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classifications to exclude. Applied after the taxonomy OR, as AND-NOT. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeSubtype`, `excludeSubtypes`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludeAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classifications to exclude. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeAssetClass`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "taxonomyMatchMode",
                        "in": "query",
                        "required": false,
                        "description": "Whether a land use has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any taxonomy level, so a project matches when it has the land use you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (projectTypes, subtypes, assetClasses). Every delivered record names which of its land uses matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the use you searched for is its primary one — that returns fewer records and bills for fewer.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "primary_only",
                                "primary_or_secondary",
                                "any"
                            ]
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "Where the project stands. Accepts the machine token or the human label (\"approved\" or \"Approved\"). \"unknown\" selects records with no decision recorded. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statuses`, `statusSelection`. Accepted values: `/api/v1/reference/statuses`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionBodies",
                        "in": "query",
                        "required": false,
                        "description": "The body that heard the request, normalised to its short name (\"Salt Lake City Council\" → \"City Council\"). Matching is exact against that short name, never a substring. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionBody`. Accepted values: `/api/v1/reference/decision-bodies`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "statusCombos",
                        "in": "query",
                        "required": false,
                        "description": "\"<body>|<status>\" pairs, e.g. \"City Council|approved\". This is what the retired CC…/PC… buckets decompose into, and it is strictly more expressive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statusCombo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requestTypes",
                        "in": "query",
                        "required": false,
                        "description": "What the applicant asked the jurisdiction for, e.g. \"rezone\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `requestType`, `applicationTypes`, `askType`, `askTypes`. Accepted values: `/api/v1/reference/request-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionTypes",
                        "in": "query",
                        "required": false,
                        "description": "The kind of action recorded on the project. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionTypes",
                        "in": "query",
                        "required": false,
                        "description": "What kind of construction the filing describes. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionMagnitudes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionIntel",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction intelligence was extracted for this record.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "ownerTypes",
                        "in": "query",
                        "required": false,
                        "description": "Who the owner is, e.g. private or public. A list is an OR. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ownerType`. Accepted values: `/api/v1/reference/owner-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "includeCivic",
                        "in": "query",
                        "required": false,
                        "description": "Include non-real-estate government decisions. Defaults to false, which is what the product shows — and which reduces what a naive query bills for. Accepted aliases: `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "civicSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "civicAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "inOpportunityZone",
                        "in": "query",
                        "required": false,
                        "description": "Whether the project site is inside a federal Opportunity Zone (2018 designation).",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "inSfha",
                        "in": "query",
                        "required": false,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Accepted aliases: `inFemaFloodZone`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "meetingDateFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateFrom`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "meetingDateTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest last-updated date. On GET /projects/sync this seeds the first cursor and is then carried inside it, so it does not need re-sending on later pages. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedFrom`, `updatedAtFrom`, `updatedSince`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest last-updated date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedTo`, `updatedAtTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "dateRange",
                        "in": "query",
                        "required": false,
                        "description": "A relative meeting-date window. Defaults to last_1_year, matching what the product shows. Pass dateRange=all to search the whole corpus.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "last_3_months",
                                "last_6_months",
                                "last_1_year",
                                "since_jan_2025",
                                "all"
                            ]
                        }
                    },
                    {
                        "name": "totalUnitCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Keyword search. Several words are matched as an exact phrase; pipe-separated groups (\"mixed use|apartments\") are alternatives. Accepted aliases: `search`, `query`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Sort field. Aliases ending in `_newest`, `_oldest`, `_highest`, or `_lowest` encode their direction.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "meetingDate",
                                "lastUpdated",
                                "dataRichness",
                                "totalUnitCount",
                                "acreage",
                                "meeting_date",
                                "meeting_date_newest",
                                "meeting_date_oldest",
                                "updated_at",
                                "data_richness",
                                "units_highest",
                                "units_lowest",
                                "acres_highest",
                                "acres_lowest"
                            ],
                            "default": "meetingDate"
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "description": "Sort direction. Field-only sorts default to desc. Omit it for a direction-bearing sort alias, or use the matching direction; conflicts return 400.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "Results per page (1–100).",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "description": "Pagination offset (0-based). Prefer this when paging. Mutually exclusive with `page` when both are sent: offset wins.",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "description": "1-based page number. When `offset` is omitted, treated as `offset = (page - 1) * limit`.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "default": 1
                        }
                    },
                    {
                        "name": "format",
                        "in": "query",
                        "description": "Response format. `json` (default) returns the standard `{data, meta}` page. `csv` queues a product CSV export job (same writer as the map Export CSV button), returns HTTP 202 with export job + download URLs, and lists the file on `/exports`. Add `include=contacts` on a paid plan to turn on Find Contact Info for those rows.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "json",
                                "csv"
                            ],
                            "default": "json"
                        }
                    },
                    {
                        "name": "include",
                        "in": "query",
                        "description": "Set to `contacts` to turn on Find Contact Info for the projects in this request (paid plans only). On JSON search this requires `contactOptions.cachedOnly=true`. On `format=csv` it queues the same live lookup as the website export toggle.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "contacts"
                            ]
                        }
                    },
                    {
                        "name": "contactOptions",
                        "in": "query",
                        "description": "JSON object of contact options. On synchronous JSON search, `cachedOnly` must be true. Not valid with `format=csv`.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "{\"cachedOnly\":true}"
                    },
                    {
                        "name": "deliveryMode",
                        "in": "query",
                        "description": "Only `all` is currently supported; delivery state is disclosed on each record.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all"
                            ],
                            "default": "all"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "JSON page of projects with pagination + credit usage metadata. Also returned with `format=csv` when the page would be empty (no export job is created).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProjectSearchResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "202": {
                        "description": "`format=csv`: export job accepted. Poll `pollUrl` / download via `downloadUrl`. Same file appears on the product `/exports` page. `include=contacts` (paid) runs Find Contact Info on those rows.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CsvExportJobAccepted"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/UnknownRepresentation"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "501": {
                        "$ref": "#/components/responses/EnrichmentUnavailable"
                    },
                    "503": {
                        "$ref": "#/components/responses/SearchUnavailable"
                    }
                }
            }
        },
        "/projects/count": {
            "get": {
                "tags": [
                    "Projects"
                ],
                "summary": "Count matching projects and price the request — free",
                "description": "How many projects match a filter set, and what fetching them would cost. **Free: zero credits, and no balance row is created.**\n\nAccepts **exactly** the filter vocabulary of `GET /projects/search`, so you can count and then fetch with the identical query string. Paging parameters are accepted and ignored — a page size cannot change how many records match.\n\n**It returns no record identity of any kind:** no ids, no names, no sample records, no facets.\n\n**What you pay is not always what you match.** A record your credit pool has already received, and which has not changed since, ships again for free — so `billable.records` can be lower than `matchCount`, and the `402` threshold is the former. A second identical request costs less than the first.\n\n**Honest counts.** The search engine enumerates at most 10,000 candidates for one request. Above that, `matchCountIsExact` is `false`, `matchCountBasis` is `scan_ceiling_reached`, and `matchCount` is a lower bound — render it as \"10,000+\", never \"10,000\".\n\n**Credits are not checked here.** A pool with zero credits still receives a `200`; a lapsed subscription is refused `402`, because the free plane is entitled rather than public.\n\nFull policy: https://boardwalkai.com/docs/api/budgets/",
                "parameters": [
                    {
                        "name": "states",
                        "in": "query",
                        "required": false,
                        "description": "States, as numeric ids, USPS abbreviations (\"UT\") or full names (\"Utah\"). A list is an OR: pass every state you want. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `state`, `stateId`, `stateIds`. Accepted values: `/api/v1/locations/states`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "counties",
                        "in": "query",
                        "required": false,
                        "description": "Counties, as numeric ids or names (a trailing \"County\" is optional). A name is resolved against a single `states` value when one is given. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `county`, `countyId`, `countyIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "cities",
                        "in": "query",
                        "required": false,
                        "description": "Cities, as numeric ids or names. A name is resolved against a single `states`/`counties` value when one is given; an ambiguous name is an error, never a silently wider search. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `city`, `cityId`, `cityIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties/{countyId}/cities`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "bbox",
                        "in": "query",
                        "required": false,
                        "description": "Rectangle {north, south, east, west}. Records are returned only when their coordinates fall inside the rectangle — the engine prefilters with a circle and the corners of that circle are then removed. Accepted aliases: `bounds`. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "circle",
                        "in": "query",
                        "required": false,
                        "description": "Radius search {lat, lng, radiusMeters}. radiusMeters is 100–500000. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "polygon",
                        "in": "query",
                        "required": false,
                        "description": "GeoJSON linear ring [[lng, lat], …], 4–1000 vertices, first vertex equal to last. The engine prefilters with the ring's bounding circle and exact point-in-polygon runs afterwards. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertyTypes",
                        "in": "query",
                        "required": false,
                        "description": "Top-level land-use classification, e.g. \"Residential\". Case-insensitive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `type`, `types`, `propertyType`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classification. Also accepts \"Type - Subtype\" compounds, which are split server-side. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `subtype`, `subtypes`, `propertySubtype`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "assetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classification, e.g. \"Apartment Building\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `assetClass`, `assetClasses[]`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludePropertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classifications to exclude. Applied after the taxonomy OR, as AND-NOT. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeSubtype`, `excludeSubtypes`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludeAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classifications to exclude. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeAssetClass`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "taxonomyMatchMode",
                        "in": "query",
                        "required": false,
                        "description": "Whether a land use has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any taxonomy level, so a project matches when it has the land use you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (projectTypes, subtypes, assetClasses). Every delivered record names which of its land uses matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the use you searched for is its primary one — that returns fewer records and bills for fewer.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "primary_only",
                                "primary_or_secondary",
                                "any"
                            ]
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "Where the project stands. Accepts the machine token or the human label (\"approved\" or \"Approved\"). \"unknown\" selects records with no decision recorded. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statuses`, `statusSelection`. Accepted values: `/api/v1/reference/statuses`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionBodies",
                        "in": "query",
                        "required": false,
                        "description": "The body that heard the request, normalised to its short name (\"Salt Lake City Council\" → \"City Council\"). Matching is exact against that short name, never a substring. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionBody`. Accepted values: `/api/v1/reference/decision-bodies`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "statusCombos",
                        "in": "query",
                        "required": false,
                        "description": "\"<body>|<status>\" pairs, e.g. \"City Council|approved\". This is what the retired CC…/PC… buckets decompose into, and it is strictly more expressive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statusCombo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requestTypes",
                        "in": "query",
                        "required": false,
                        "description": "What the applicant asked the jurisdiction for, e.g. \"rezone\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `requestType`, `applicationTypes`, `askType`, `askTypes`. Accepted values: `/api/v1/reference/request-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionTypes",
                        "in": "query",
                        "required": false,
                        "description": "The kind of action recorded on the project. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionTypes",
                        "in": "query",
                        "required": false,
                        "description": "What kind of construction the filing describes. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionMagnitudes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionIntel",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction intelligence was extracted for this record.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "ownerTypes",
                        "in": "query",
                        "required": false,
                        "description": "Who the owner is, e.g. private or public. A list is an OR. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ownerType`. Accepted values: `/api/v1/reference/owner-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "includeCivic",
                        "in": "query",
                        "required": false,
                        "description": "Include non-real-estate government decisions. Defaults to false, which is what the product shows — and which reduces what a naive query bills for. Accepted aliases: `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "civicSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "civicAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "inOpportunityZone",
                        "in": "query",
                        "required": false,
                        "description": "Whether the project site is inside a federal Opportunity Zone (2018 designation).",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "inSfha",
                        "in": "query",
                        "required": false,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Accepted aliases: `inFemaFloodZone`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "meetingDateFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateFrom`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "meetingDateTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest last-updated date. On GET /projects/sync this seeds the first cursor and is then carried inside it, so it does not need re-sending on later pages. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedFrom`, `updatedAtFrom`, `updatedSince`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest last-updated date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedTo`, `updatedAtTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "dateRange",
                        "in": "query",
                        "required": false,
                        "description": "A relative meeting-date window. Defaults to last_1_year, matching what the product shows. Pass dateRange=all to search the whole corpus.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "last_3_months",
                                "last_6_months",
                                "last_1_year",
                                "since_jan_2025",
                                "all"
                            ]
                        }
                    },
                    {
                        "name": "totalUnitCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Keyword search. Several words are matched as an exact phrase; pipe-separated groups (\"mixed use|apartments\") are alternatives. Accepted aliases: `search`, `query`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Ordering field. Accepts the identical values as `/projects/search` and is echoed back in `data.ordering` with what it means. Aliases ending in `_newest`, `_oldest`, `_highest`, or `_lowest` encode their direction.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "meetingDate",
                                "lastUpdated",
                                "dataRichness",
                                "totalUnitCount",
                                "acreage",
                                "meeting_date",
                                "meeting_date_newest",
                                "meeting_date_oldest",
                                "updated_at",
                                "data_richness",
                                "units_highest",
                                "units_lowest",
                                "acres_highest",
                                "acres_lowest"
                            ],
                            "default": "meetingDate"
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "description": "Sort direction. Field-only sorts default to desc. Omit it for a direction-bearing sort alias, or use the matching direction; conflicts return 400.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The match count, the price, and whether this caller can afford it. Nothing is charged.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProjectCountResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/UnknownRepresentation"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "503": {
                        "$ref": "#/components/responses/SearchUnavailable"
                    }
                }
            }
        },
        "/projects/sync": {
            "get": {
                "tags": [
                    "Projects"
                ],
                "summary": "Incremental sync — everything new or changed, with no gaps",
                "description": "Walks your entitled corpus in last-updated order and hands back a cursor. Send the cursor on the next call to continue exactly where you stopped.\n\n**Why not `?updatedSince=`.** A timestamp watermark walked with `offset` loses records silently: anything that changes while you are paging moves in the sort order, and whatever crosses the page boundary behind you is never returned. This route's cursor is a position in a total order (`lastUpdated` ascending, then id), and `lastUpdated` only ever moves forward — so a record that changes mid-walk moves *ahead* of you and is still delivered. It can hand you a record twice; it cannot skip one.\n\n**Cost: 1 credit per record that is new to you or whose content has changed.** Records you already hold and that have not changed are returned again for free, with `delivery.alreadyExported: true` and `delivery.updatedSinceExport: false`. A page that is entirely re-delivery costs nothing and is served even at a zero balance.\n\n**What changed.** Every record whose content moved carries `delivery.changedGroups`, `delivery.changes` (before/after for the monitored fields), `delivery.newEvidence` (public filings you had not seen) and a plain-language `delivery.changeSummary`.\n\n**Starting over.** Omit `cursor`. That is the whole reset path: it re-walks everything and bills only what genuinely changed since we last delivered it, which for a mirror that is up to date is nothing.\n\n**Ordering is fixed.** `sort`, `order`, `offset` and `page` are refused here — the ordering is what makes the walk lossless. Use `GET /projects/search` when you want to choose it.",
                "parameters": [
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "The `meta.sync.cursor` value from your previous page. Omit it to start (or restart) a sync.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "Records per page (1–100).",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "states",
                        "in": "query",
                        "required": false,
                        "description": "States, as numeric ids, USPS abbreviations (\"UT\") or full names (\"Utah\"). A list is an OR: pass every state you want. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `state`, `stateId`, `stateIds`. Accepted values: `/api/v1/locations/states`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "counties",
                        "in": "query",
                        "required": false,
                        "description": "Counties, as numeric ids or names (a trailing \"County\" is optional). A name is resolved against a single `states` value when one is given. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `county`, `countyId`, `countyIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "cities",
                        "in": "query",
                        "required": false,
                        "description": "Cities, as numeric ids or names. A name is resolved against a single `states`/`counties` value when one is given; an ambiguous name is an error, never a silently wider search. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `city`, `cityId`, `cityIds`. Accepted values: `/api/v1/locations/states/{stateId}/counties/{countyId}/cities`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "bbox",
                        "in": "query",
                        "required": false,
                        "description": "Rectangle {north, south, east, west}. Records are returned only when their coordinates fall inside the rectangle — the engine prefilters with a circle and the corners of that circle are then removed. Accepted aliases: `bounds`. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "circle",
                        "in": "query",
                        "required": false,
                        "description": "Radius search {lat, lng, radiusMeters}. radiusMeters is 100–500000. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "polygon",
                        "in": "query",
                        "required": false,
                        "description": "GeoJSON linear ring [[lng, lat], …], 4–1000 vertices, first vertex equal to last. The engine prefilters with the ring's bounding circle and exact point-in-polygon runs afterwards. Encode this value as JSON in the query string.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertyTypes",
                        "in": "query",
                        "required": false,
                        "description": "Top-level land-use classification, e.g. \"Residential\". Case-insensitive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `type`, `types`, `propertyType`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "propertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classification. Also accepts \"Type - Subtype\" compounds, which are split server-side. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `subtype`, `subtypes`, `propertySubtype`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "assetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classification, e.g. \"Apartment Building\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `assetClass`, `assetClasses[]`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludePropertySubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Second-level classifications to exclude. Applied after the taxonomy OR, as AND-NOT. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeSubtype`, `excludeSubtypes`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "excludeAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Third-level classifications to exclude. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `excludeAssetClass`. Accepted values: `/api/v1/taxonomy`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "taxonomyMatchMode",
                        "in": "query",
                        "required": false,
                        "description": "Whether a land use has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any taxonomy level, so a project matches when it has the land use you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (projectTypes, subtypes, assetClasses). Every delivered record names which of its land uses matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the use you searched for is its primary one — that returns fewer records and bills for fewer.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "primary_only",
                                "primary_or_secondary",
                                "any"
                            ]
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "Where the project stands. Accepts the machine token or the human label (\"approved\" or \"Approved\"). \"unknown\" selects records with no decision recorded. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statuses`, `statusSelection`. Accepted values: `/api/v1/reference/statuses`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionBodies",
                        "in": "query",
                        "required": false,
                        "description": "The body that heard the request, normalised to its short name (\"Salt Lake City Council\" → \"City Council\"). Matching is exact against that short name, never a substring. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionBody`. Accepted values: `/api/v1/reference/decision-bodies`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "statusCombos",
                        "in": "query",
                        "required": false,
                        "description": "\"<body>|<status>\" pairs, e.g. \"City Council|approved\". This is what the retired CC…/PC… buckets decompose into, and it is strictly more expressive. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `statusCombo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requestTypes",
                        "in": "query",
                        "required": false,
                        "description": "What the applicant asked the jurisdiction for, e.g. \"rezone\". Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `requestType`, `applicationTypes`, `askType`, `askTypes`. Accepted values: `/api/v1/reference/request-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "decisionTypes",
                        "in": "query",
                        "required": false,
                        "description": "The kind of action recorded on the project. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `decisionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionTypes",
                        "in": "query",
                        "required": false,
                        "description": "What kind of construction the filing describes. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionType`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionMagnitudes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionIntel",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction intelligence was extracted for this record.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "ownerTypes",
                        "in": "query",
                        "required": false,
                        "description": "Who the owner is, e.g. private or public. A list is an OR. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ownerType`. Accepted values: `/api/v1/reference/owner-types`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "includeCivic",
                        "in": "query",
                        "required": false,
                        "description": "Include non-real-estate government decisions. Defaults to false, which is what the product shows — and which reduces what a naive query bills for. Accepted aliases: `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "civicSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "civicAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows the civic side only. Requires includeCivic=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "inOpportunityZone",
                        "in": "query",
                        "required": false,
                        "description": "Whether the project site is inside a federal Opportunity Zone (2018 designation).",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "inSfha",
                        "in": "query",
                        "required": false,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Accepted aliases: `inFemaFloodZone`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inside",
                                "outside"
                            ]
                        }
                    },
                    {
                        "name": "meetingDateFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateFrom`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "meetingDateTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest meeting date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `dateTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedFrom",
                        "in": "query",
                        "required": false,
                        "description": "Earliest last-updated date. On GET /projects/sync this seeds the first cursor and is then carried inside it, so it does not need re-sending on later pages. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedFrom`, `updatedAtFrom`, `updatedSince`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lastUpdatedTo",
                        "in": "query",
                        "required": false,
                        "description": "Latest last-updated date. Accepts YYYY, YYYY-MM, YYYY-MM-DD or RFC3339. Inclusive: a \"To\" bound snaps to the END of the period named. Accepted aliases: `updatedTo`, `updatedAtTo`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "dateRange",
                        "in": "query",
                        "required": false,
                        "description": "A relative meeting-date window. Defaults to last_1_year, matching what the product shows. Pass dateRange=all to search the whole corpus.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "last_3_months",
                                "last_6_months",
                                "last_1_year",
                                "since_jan_2025",
                                "all"
                            ]
                        }
                    },
                    {
                        "name": "totalUnitCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for totalUnitCount, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acreage, in acres. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for lotSizeSqft, in sqft. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for squareFootage, in sqft. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "parkingSpacesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for parkingSpaces, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingStoriesMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingStories, in count. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `storiesMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "buildingHeightFeetMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for buildingHeightFeet, in feet. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `buildingHeightFtMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "bedroomCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for bedroomCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "floorCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for floorCount, in count. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Keyword search. Several words are matched as an exact phrase; pipe-separated groups (\"mixed use|apartments\") are alternatives. Accepted aliases: `search`, `query`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of the walk, plus the cursor for the next one.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProjectSyncResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "An unknown parameter, an unusable cursor (`invalid_cursor`, with `details.reason`), or an ordering parameter this route does not accept. Nothing is charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "503": {
                        "description": "More records share one `lastUpdated` second than a page can order (`sync_tie_unresolved`), so continuing could leave a gap. Nothing is delivered and nothing is charged; narrow the query and retry with the same cursor.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/projects/{id}": {
            "get": {
                "tags": [
                    "Projects"
                ],
                "summary": "Get a single project",
                "description": "Returns one project record by its integer `id` — the same record shape `/projects/search` returns, at whichever `representation` you ask for.\n\n**Cost: 1 credit.** A `404` costs nothing.\n\nA project is served only where our current-generation extraction has covered it; ids outside that set return `404` and are not charged. Recently ingested projects are the most likely to be in that state.\n\nIf this record has already been delivered to your credit pool and has not changed since, it is returned **without being charged again** — see the `delivery` block on every record.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Project ID (integer).",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The project record.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProjectDetailResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/UnknownRepresentation"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "404": {
                        "description": "No project is available for this ID. No credits are charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/projects/ai-search": {
            "post": {
                "tags": [
                    "Projects"
                ],
                "summary": "Natural-language project search (AI, synchronous)",
                "description": "Synchronous AI search. Prefer `POST /projects/ai-search/jobs` for API integrations that may wait minutes.\n\nSend a free-form query like \"large apartment complexes near downtown Salt Lake City approved in the last 6 months\". An LLM parses the query into structured filters and the result set is built from a blend of semantic vector similarity, BM25 text matching, and the structured filters. Index-compatible parsed criteria are embedded in every retrieval channel rather than used as a capped ranking sample. Status, decision type, date, and supported measurement criteria are rechecked against the record that can actually be returned before delivery and billing; missing current evidence is a non-match. If the query parser is unavailable, the request fails without billing instead of widening the search. Requirements involving drive-throughs, square footage, wetlands, architectural style, amenities, ownership type, or required affordable units cannot yet be proved against the returned record and are rejected with `400` rather than treated as loose text preferences. Evidence-dependent requirements such as community opposition, controversy, traffic concerns, or proximity to schools require the grounded async route and receive a synchronous `400` with its endpoint.\n\n**Cost: 1 credit per returned project that is new or changed.** Unchanged re-deliveries are returned free — the same rule as every other record-returning endpoint.\n\n`limit` is 1–100. The synchronous result window is 100 ranked candidates, so `offset + limit` may not exceed **100**. Use the asynchronous route for a deeper window.\n\nOptional geographic body filters (`stateIds`, `countyIds`, `cityIds`) must be **integer IDs** from `/locations/*`, not abbreviations or place names. Each individual geography array accepts at most **100 raw items** (duplicates count). After deduplication, a request may contain at most **100 unique IDs total** across all geography fields and aliases.\n\nThe response includes `meta.parsedQuery` showing what the LLM extracted, which is useful for debugging unexpected results.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AiSearchRequest"
                            },
                            "example": {
                                "query": "multifamily apartment buildings over 100 units approved in Utah in 2025",
                                "limit": 25,
                                "sort": "meeting_date",
                                "order": "desc"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "AI-ranked project results with parsed-query diagnostics.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing or empty `query`/`q`, unknown body fields, invalid controls/filters, or an AI constraint that cannot be verified against returned records. Nothing is charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "503": {
                        "description": "AI search index is temporarily unavailable. Retry shortly.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/projects/ai-search/jobs": {
            "post": {
                "tags": [
                    "Projects"
                ],
                "summary": "Start an asynchronous AI search job",
                "description": "Queues a natural-language AI search and returns a `requestId` immediately (`202 Accepted`). Poll `GET /projects/ai-search/jobs/{requestId}` until `status` is one of the terminal values: `completed`, `partial`, `failed`, `cancelled`, or `expired`.\n\nIndex-compatible parsed criteria are embedded in every retrieval channel rather than used as a capped ranking sample. Status, decision type, date, and supported measurement criteria are rechecked before a semantic confirmation can fill the requested page and again before delivery and billing. Missing current evidence is a non-match. Parser or gate failures fail the job and refund its reservation instead of widening the search. Requirements involving drive-throughs, square footage, wetlands, architectural style, amenities, ownership type, or required affordable units cannot yet be proved against the returned record and are rejected with `400` before a job is queued or credits are reserved.\n\n**Credits:** reserves `limit` credits at submit (1 per record). On completion, charges 1 credit for each delivered record that is new or changed; unchanged re-deliveries are free, and all unused reserved credits are refunded. Failures refund the full reservation.\n\nEach job returns at most **100 records** (`limit` is 1–100). The asynchronous route supports a deeper confirmed-match window for paging: `offset + limit` may not exceed **1,000**.\n\nGeography filters follow the synchronous request contract: integer location IDs only. Each individual geography array accepts at most **100 raw items** (duplicates count); after deduplication, at most **100 unique IDs total** may appear across all geography fields and aliases.\n\nCompleted or partial results include record-level `aiMatch` evidence plus `meta.parsedQuery` and `meta.matchesByProjectId`. The worker enforces a separate daily screening budget atomically; reaching it can settle a job as `partial` with `partialReason: daily_ai_budget_exhausted` rather than pretending the result is complete.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AiSearchRequest"
                            },
                            "example": {
                                "query": "multifamily apartment buildings over 100 units approved in Utah in 2025",
                                "limit": 25,
                                "sort": "meeting_date",
                                "order": "desc"
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "Job accepted; poll the returned `pollUrl`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchJobAccepted"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing or empty `query`/`q`, unknown body fields, invalid controls/filters, or an AI constraint that cannot be verified against returned records. No job is queued and no credits are reserved.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "501": {
                        "$ref": "#/components/responses/EnrichmentUnavailable"
                    },
                    "503": {
                        "description": "AI search index is temporarily unavailable. Retry shortly.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/projects/ai-search/jobs/{id}": {
            "get": {
                "tags": [
                    "Projects"
                ],
                "summary": "Poll an asynchronous AI search job",
                "description": "Returns job status. While `queued` or `running`, `data` is null and `progress` reports screening work. `completed` and `partial` return real, billed results; `cancelled`, `failed`, and `expired` are terminal without results.\n\nPolling does not charge additional credits.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Job `requestId` from the create response.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Current job status and, when available, progress or results.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchJobStatus"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "Job not found for this API user.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "410": {
                        "description": "Completed result expired (retained 72 hours). Body uses the same job-status schema with `status: expired`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchJobStatus"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/documents/{id}": {
            "get": {
                "tags": [
                    "Documents"
                ],
                "summary": "Get a single meeting document",
                "description": "Returns the full meeting document record — title, meeting date, raw extracted text, structured analysis, and source URL.\n\nThese are the underlying source records that projects were extracted from. `id` values are returned in project responses under `documentDetails[].id`.\n\nOnly documents that have been through Boardwalk's current extraction standard are served here; a document that has not been analysed returns `404` and is not charged. Documents ingested in the last few weeks are the most likely to be in that state.\n\n**Cost: 1 credit per request.** A `404` costs nothing.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Meeting document ID.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Document record.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/DocumentResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "No document is available for this ID — it does not exist, or it has not been analysed. No credits are charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Full land use taxonomy tree",
                "description": "Three-level hierarchy: project types → subtypes → asset classes. Use these labels when constructing `type`, `subtype`, and `assetClass` filters for `/projects/search`. Free.",
                "responses": {
                    "200": {
                        "description": "Taxonomy tree.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TaxonomyTreeResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy/project-types": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Top-level project types",
                "description": "Just the level-1 labels (Residential, Commercial, Industrial, …). Free.",
                "responses": {
                    "200": {
                        "description": "List of project type labels.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LabelListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy/subtypes": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Project subtypes",
                "description": "Level-2 labels, optionally scoped to a parent project type. Free.",
                "parameters": [
                    {
                        "name": "projectType",
                        "in": "query",
                        "description": "Optional parent project type filter (e.g. `Residential`).",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of subtype labels.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LabelListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy/asset-classes": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Asset classes",
                "description": "Level-3 labels, optionally scoped to a parent project type and/or subtype. Free.",
                "parameters": [
                    {
                        "name": "projectType",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "subType",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of asset class labels.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LabelListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy/action-types": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Action / decision types",
                "description": "Action type labels for the `decisionType` filter on `/projects/search`. Optionally filtered by category. Free.",
                "parameters": [
                    {
                        "name": "category",
                        "in": "query",
                        "description": "Optional action category filter (e.g. `Land Use & Zoning`).",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of action types.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LabelListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy/action-categories": {
            "get": {
                "tags": [
                    "Taxonomy"
                ],
                "summary": "Action categories",
                "description": "Top-level action category labels (parents of action types). Free.",
                "responses": {
                    "200": {
                        "description": "List of action category labels.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LabelListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/states": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "List all states",
                "description": "States in the catalogue with numeric IDs, names, and approximate centroid coordinates. Coverage is per-state. On search/count/analytics you may send `states` as ids, USPS abbreviations (e.g. `UT`), or full names — they resolve to ids for lookup. Free.",
                "responses": {
                    "200": {
                        "description": "List of states.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/StateListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/states/{id}": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "Get one state",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "State record.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/StateResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "State not found.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/states/{id}/counties": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "List counties in a state",
                "description": "County IDs for the `countyIds` filter (legacy `county`) on `/projects/search`. Free.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "State ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of counties.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CountyListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "State not found.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/states/{stateId}/counties/{countyId}/cities": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "List cities in a county",
                "parameters": [
                    {
                        "name": "stateId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "countyId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of cities.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CityListResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "County not found in the specified state.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/counties/{id}": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "Get one county",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "County record.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CountyDetailResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "County not found.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/locations/cities/{id}": {
            "get": {
                "tags": [
                    "Locations"
                ],
                "summary": "Get one city",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "City record.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CityDetailResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "City not found.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/account/credits": {
            "get": {
                "tags": [
                    "Account"
                ],
                "summary": "Credit balance and plan info",
                "description": "Returns the current billing-period credit balance and the rate limit for the authenticated API key. Free.",
                "responses": {
                    "200": {
                        "description": "Credit balance.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CreditBalanceResponse"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    }
                }
            }
        },
        "/analytics/datasets": {
            "get": {
                "tags": [
                    "Analytics"
                ],
                "summary": "Describe the analytics surface — free",
                "description": "**Free.** What you can group by, what you can measure, what each metric's denominator is, and — deliberately — **the questions this data cannot answer**, each with the measurement that rules it out.\n\nRead `notAnswerable` before designing an integration. It is not a disclaimer: denial rates, approval-rate rankings, time-to-decision and valuation are not thin here, they are absent, and building against them would produce confident wrong answers.\n\nReturns no project data of any kind.",
                "responses": {
                    "200": {
                        "description": "The analytics catalog: datasets, groupable fields, metrics with their denominators, limits, excluded fields with reasons, unanswerable questions, and worked example requests.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    }
                }
            }
        },
        "/analytics/aggregate": {
            "post": {
                "tags": [
                    "Analytics"
                ],
                "summary": "Group and measure matching projects — free, no record identity",
                "description": "**Free: zero credits, and no balance row is created.** Answers \"how many, of what kind, where, and when\" without delivering a single billable record.\n\n`filters` takes **exactly** the vocabulary of `GET /projects/search`, so an aggregate row can be taken straight to `/projects/count` and then to `/projects/search` with the same filters. The numbers agree with those endpoints by construction: the same merge collapse and the same record gate run before anything is grouped.\n\n**Every metric carries a `coverage` fraction** — the share of the group that actually had the underlying field. Read it before quoting a sum: unit counts are populated on a minority of records, so a summed unit figure describes the records that have one, not the market.\n\n**Small groups are suppressed.** Any group with fewer than 5 projects is dropped and counted in `suppressed`, and a grand total below 5 is withheld as well. This is a privacy floor, not a bug: without it a narrow enough filter set would identify a single project.\n\nUnknown parameters, unknown fields and unknown metrics return `400` with the valid set attached — nothing is silently ignored, because a silently coarser grouping is a plausible wrong answer.",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                    "dataset": {
                                        "type": "string",
                                        "enum": [
                                            "projects"
                                        ],
                                        "default": "projects"
                                    },
                                    "filters": {
                                        "type": "object",
                                        "description": "The same filter vocabulary as `GET /projects/search`."
                                    },
                                    "groupBy": {
                                        "type": "array",
                                        "maxItems": 3,
                                        "items": {
                                            "type": "string"
                                        },
                                        "description": "Field names from `GET /analytics/datasets`. At most 3."
                                    },
                                    "metrics": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "default": [
                                            "count"
                                        ]
                                    },
                                    "orderBy": {
                                        "type": "string",
                                        "default": "count",
                                        "description": "A metric name. Added to `metrics` if not already requested."
                                    },
                                    "direction": {
                                        "type": "string",
                                        "enum": [
                                            "asc",
                                            "desc"
                                        ],
                                        "default": "desc"
                                    },
                                    "limit": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 1000,
                                        "default": 50
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Groups with their metrics and coverage fractions, grand totals, and what was suppressed. No record identity.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Unknown parameter, field, or metric, or a limit exceeded. `details.problems[]` names each one and lists the valid values. Nothing is charged — this endpoint is free.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "503": {
                        "description": "Project search is temporarily unavailable, so no aggregate could be produced. Never reported as a count of zero.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/analytics/rankings": {
            "post": {
                "tags": [
                    "Analytics"
                ],
                "summary": "Rank places by a metric, with a denominator — free",
                "description": "**Free: zero credits, no record identity.** A leaderboard over a geographic grain, which is deliberately a separate endpoint from `/analytics/aggregate` rather than a sort on it.\n\nThe difference is `minDenominator`. The most common way a ranking lies is a top row computed over one project, and a caller assembling a leaderboard out of a group-by gets no denominator floor and does not know it is missing one. Rows below the floor are **excluded and counted**, never silently absent.\n\nEvery row carries its `denominator`, its `coverage`, and a `comparison.baseline` — the same metric over the whole filtered set — so a row can be read as a share of the market rather than as a bare number.\n\n`minDenominator` cannot be set below the suppression floor of 5.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                    "rankBy",
                                    "over"
                                ],
                                "properties": {
                                    "dataset": {
                                        "type": "string",
                                        "enum": [
                                            "projects"
                                        ],
                                        "default": "projects"
                                    },
                                    "filters": {
                                        "type": "object",
                                        "description": "The same filter vocabulary as `GET /projects/search`."
                                    },
                                    "rankBy": {
                                        "type": "string",
                                        "description": "A rankable metric from `GET /analytics/datasets`."
                                    },
                                    "over": {
                                        "type": "string",
                                        "enum": [
                                            "city",
                                            "county",
                                            "state"
                                        ]
                                    },
                                    "direction": {
                                        "type": "string",
                                        "enum": [
                                            "asc",
                                            "desc"
                                        ],
                                        "default": "desc"
                                    },
                                    "limit": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 100,
                                        "default": 10
                                    },
                                    "minDenominator": {
                                        "type": "integer",
                                        "minimum": 5,
                                        "default": 10
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Ranked rows with denominators, coverage and a comparison baseline, plus what was excluded and why.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Unknown or unrankable metric, a non-geographic `over`, or a `minDenominator` below the suppression floor. Nothing is charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "503": {
                        "description": "Project search is temporarily unavailable. Never reported as an empty ranking.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts": {
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "List the alerts you can see — free",
                "description": "Every alert your **membership** resolves: the ones you created, plus the ones shared with you (`share.mode` of `team` or `custom`). An alert on the same account that is not shared with your key's user does not appear — visibility follows membership, not the billing account. **Free.**\n\n`meta.activeAlerts` counts the whole account against the cap, so it can be higher than the number of alerts returned.",
                "parameters": [
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Your alerts, plus how many of the per-account maximum are in use.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            },
            "post": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Create an alert — free",
                "description": "Creates a standing instruction: a preset search that runs on a cadence. **Free — creating, previewing, editing and deleting an alert never cost credits.** You are charged only for records a run delivers, once each, and never again for a record you already hold that has not changed.\n\n`filters` is **exactly** the vocabulary of `GET /projects/search`, validated by the same registry: an unknown parameter or an unknown value is a `400`, and nothing is stored. There is no third outcome in which a filter is accepted and then quietly not applied.\n\n**Geography is required.** An alert with no `states`, `counties`, `cities` or geometry is refused — a blank geography field is almost never a request for the whole country.\n\n**Sharing.** `share.mode` is `private` (default — only you), `team` (everyone on your current team roster, present and future, minus `share.optOutUserIds`), or `custom` (exactly the people in `share.userIds`, plus you). Members get an email when they are added, every member holds the full surface — read, edit, run, dismiss, delete — and `share.userIds` must come from your own team's roster: sharing across accounts is impossible by construction. Sharing needs a team on a paid plan (`403 sharing_requires_paid_plan` otherwise; the refused create stores nothing). Every alert response carries a `share` block with the **live** member list.\n\nLimits: 25 active alerts per account, 5 states or 25 counties/cities per alert, and up to 1,000 records materialised per run.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "filters"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "filters": {
                                        "type": "object",
                                        "description": "The same filter vocabulary as `GET /projects/search`. Window and paging parameters are refused: the window comes from the cadence."
                                    },
                                    "cadence": {
                                        "type": "object",
                                        "properties": {
                                            "frequency": {
                                                "type": "string",
                                                "enum": [
                                                    "manual",
                                                    "daily",
                                                    "weekly",
                                                    "monthly"
                                                ],
                                                "default": "weekly",
                                                "description": "`manual` is a saved search you run on demand and is never scheduled. `immediate` is retired and returns 400."
                                            },
                                            "timezone": {
                                                "type": "string",
                                                "default": "America/Denver",
                                                "description": "IANA zone. The send hour is your local hour."
                                            },
                                            "hourLocal": {
                                                "type": "integer",
                                                "minimum": 0,
                                                "maximum": 23,
                                                "default": 7
                                            },
                                            "backfillDays": {
                                                "type": "integer",
                                                "minimum": 0,
                                                "maximum": 90,
                                                "default": 7,
                                                "description": "How far the FIRST run looks back. Preview before raising it."
                                            }
                                        }
                                    },
                                    "maxRecordsPerRun": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 1000,
                                        "default": 100
                                    },
                                    "deliveryMode": {
                                        "type": "string",
                                        "enum": [
                                            "all"
                                        ],
                                        "default": "all",
                                        "description": "`new`, `updated` and `new_and_updated` are reserved and return 400. Every delivery returns everything it matched and discloses each record's state; the unchanged ones are free."
                                    },
                                    "notify": {
                                        "type": "object",
                                        "properties": {
                                            "email": {
                                                "type": "boolean",
                                                "default": true
                                            },
                                            "emailTo": {
                                                "type": "array",
                                                "maxItems": 5,
                                                "items": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "description": "Extra addresses to notify, **in addition to** the members' own digests — a CC list, not a replacement. Members always receive their digest; `emailTo` addresses receive a non-personalised pointer."
                                            },
                                            "webhookUrl": {
                                                "type": "string",
                                                "format": "uri",
                                                "description": "https only. Receives an `alert.delivered` pointer event — never records."
                                            }
                                        }
                                    },
                                    "share": {
                                        "type": "object",
                                        "description": "Who can see and operate this alert. Omitted means `private`. Requires a team on a paid plan for `team`/`custom` (`403 sharing_requires_paid_plan`).",
                                        "properties": {
                                            "mode": {
                                                "type": "string",
                                                "enum": [
                                                    "private",
                                                    "team",
                                                    "custom"
                                                ],
                                                "default": "private",
                                                "description": "`private`: only you. `team`: your current team roster, dynamically — people who join the team later are included. `custom`: exactly `share.userIds`, plus you."
                                            },
                                            "userIds": {
                                                "type": "array",
                                                "items": {
                                                    "type": "integer"
                                                },
                                                "description": "Only with `mode: custom`, where it is required and non-empty on create. Integer user ids from **your own team roster** — an outsider id is a `400` naming it. You are always a member and need not list yourself."
                                            },
                                            "optOutUserIds": {
                                                "type": "array",
                                                "items": {
                                                    "type": "integer"
                                                },
                                                "description": "Only with `mode: team`: roster members to leave out without freezing the roster. Adding your own id is how you leave a team-mode alert."
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The alert, including its `share` block (mode and live members). When the share added people, `meta.addedMembers` lists their user ids — the ones the \"you've been added\" email went to. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "An unknown filter parameter or value, a retired cadence, a parameter owned by the run loop, or an invalid `share` block (`error.param` names `share`, `share.mode`, `share.userIds` or `share.optOutUserIds`). Nothing was stored and nothing was charged.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "description": "A cap was reached (too many active alerts on the account, no geography, or too broad a geography) — or `sharing_requires_paid_plan`: `share.mode` was `team`/`custom` without a team on a paid plan. Either way the create was rolled back whole.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/alerts/{alertId}": {
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Read one alert — free",
                "description": "The alert's configuration plus its `share` block: `{mode, members}`, where `members` is the **live** resolution — in `team` mode, the team's current roster, with opted-out members present and flagged `optedOut: true`; in `private` mode, an empty list. Each member carries `userId`, `email`, `name`, `addedBy`, `addedAt` and `optedOut`.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "alr_01JQ8Z6X9F3K2M7T"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The alert.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id. An alert that exists but is not shared with you answers 404, never 403 — this surface never confirms an id exists.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Update an alert — free",
                "description": "Same validation as create, including the `share` block. **Any member may edit** — filters, cadence, notify and sharing alike; membership is symmetric by design.\n\nShare transitions: switching to `team` follows the roster from then on; switching to `custom` with `share.userIds` omitted keeps the current members; switching to `private` clears them. Removing the alert's last member is refused (`400`, param `share`) — delete the alert instead. A refused share rolls the whole PATCH back.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated alert. When the share transition added people, `meta.addedMembers` lists their user ids.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "An unknown filter parameter or value, or an invalid `share` block. Nothing was changed.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "`sharing_requires_paid_plan`: `share.mode` of `team`/`custom` without a team on a paid plan. The PATCH was rolled back whole.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Delete an alert — free",
                "description": "Archives the alert **for every member** — any member may do this, and the alert disappears from every member's list at once. **Its delivery history is kept**: members can still read past deliveries, and recreating an identical alert does not re-deliver and does not re-bill the records you already hold.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Archived for every member. Delivery history retained.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts/{alertId}/preview": {
            "post": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Price an alert before it runs — free",
                "description": "What this alert's **first** run would match and cost, at its own `backfillDays`. **Free.**\n\nRecords your account already holds are counted separately and cost nothing, so `creditsRequired` is the price rather than the result size. The first run at a long backfill is the most expensive single moment in this product — preview it.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Match count, whether it is exact, and the credits the first run would charge.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/GeographicAccessDenied"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            },
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Price an alert before it runs — free (GET form)",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "As POST.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts/{alertId}/run": {
            "post": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Run an alert now — billed like a scheduled run",
                "description": "Runs the alert immediately. **1 credit per delivered record that is new to your account or has changed since you last received it**; records you already hold, unchanged, ship free.\n\n`Idempotency-Key` is **required**: it is what makes a retry replay the same delivery instead of paying for it twice. A manual run that collides with a scheduled run for the same window does nothing and charges nothing.\n\nIf the run cannot afford its billable selection it delivers **nothing**, charges **nothing**, holds its window so the next run re-covers it, and returns a quote.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "The delivery: window, counts, credits charged, and the URL to fetch the records.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing Idempotency-Key.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/alerts/{alertId}/deliveries": {
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "The alert's change feed — free",
                "description": "Each run produces a numbered delivery: an immutable, already-billed batch with a window and counts. Page it with `since` to walk the feed forward. **Free.**\n\nDeliveries remain readable to members even after the alert is deleted (archived) — the delivery history is the billing record, and it survives the alert.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "since",
                        "in": "query",
                        "description": "Return only deliveries after this delivery id.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "dlv_01JQ8ZB4S1H2K9"
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Deliveries, newest first.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "`since` is not a delivery of this alert.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts/{alertId}/deliveries/{deliveryId}": {
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "One run's metadata — free",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "deliveryId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Window, counts, credits charged, and — on a refused run — the quote.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No such delivery on this alert.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts/{alertId}/matches": {
            "get": {
                "tags": [
                    "Alerts"
                ],
                "summary": "The records one run delivered — free to read",
                "description": "The records themselves. **Free, every time.** They were charged when the run materialised them, so re-reading a delivery — repeatedly, from any member's key, until it expires — costs nothing.\n\nEach record carries `delivery.alreadyExported`, `delivery.updatedSinceExport`, `delivery.lastExportedAt` and `delivery.billed`, so you can tell new from changed from unchanged without a second call.\n\nDeliveries stay fetchable for 30 days. After that the records are still yours: your account is recorded as holding them, so pulling them again through search costs nothing.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "deliveryId",
                        "in": "query",
                        "required": true,
                        "description": "Which run to read. Required — an alert's matches are always the matches of one run.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "Records per page. Capped at 25 when `representation=full`, which carries the raw source text.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The delivered records. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing `deliveryId`, an unknown representation, or `limit` above 25 with `representation=full`.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert or delivery your membership resolves has these ids.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "410": {
                        "description": "The delivery has expired. The records are still yours through search, free.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/alerts/{alertId}/dismissals/{projectId}": {
            "post": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Stop this alert delivering a project — free",
                "description": "A dismissed project is removed **before** the run delivers anything, so it is never delivered and never billed again by this alert. On a shared alert the dismissal is **one living state for every member** — dismissing hides it from everyone's runs and digests, and the response attributes who dismissed it. Dismissing one member of a merged development suppresses the whole family. The project stays available through search and through your other alerts. Idempotent: 201 the first time, 200 after.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "projectId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Already dismissed.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "201": {
                        "description": "Dismissed.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id, or no such project.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Alerts"
                ],
                "summary": "Undo a dismissal — free",
                "description": "Restores the project for **every member** — any member may undo any member's dismissal; the dismissal is shared state, not personal state.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "projectId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The project can be delivered by this alert again.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No alert your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/lists": {
            "get": {
                "tags": [
                    "Lists"
                ],
                "summary": "List the saved lists you can see — free",
                "description": "Every saved list your **membership** resolves: your own, plus the ones shared with you. Lists created from an alert delegate their sharing to that alert; system lists (the app's own \"Saved\") never appear here. **Free.**\n\nEach entry carries its `lst_…` id, `source` (`manual`, `alert`, `filter`, `polygon`), `share` block (`{mode, userIds, optOutUserIds}` — `userIds` is the live membership), and `projectCount` — `null` for `filter`/`polygon` lists, whose membership is computed by a live search rather than stored.",
                "parameters": [
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Your lists. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/lists/{listId}": {
            "get": {
                "tags": [
                    "Lists"
                ],
                "summary": "Read one list, and price its records — free",
                "description": "One list's configuration and share state, plus `results.billable` — **the free preflight for `/results`**: `results.resultCount` is how many records the list holds and `results.billable.credits` is what a full pull would charge right now, with records your account already holds unchanged priced at zero. `links.results` is the pull URL.\n\nFor a `filter`/`polygon` list the payload instead carries the stored `criteria` and `links.search` — those lists store a query, not records, and their results are priced where searches are priced.",
                "parameters": [
                    {
                        "name": "listId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "lst_01JQ8Z6X9F3K2M7T"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The list. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No list your membership resolves has this id. A list that exists but is not shared with you answers 404, never 403 — this surface never confirms an id exists.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/lists/{listId}/results": {
            "get": {
                "tags": [
                    "Lists"
                ],
                "summary": "The list's records — 1 credit per record delivered",
                "description": "The saved records themselves, hydrated and shaped **now** through the same pipeline as `GET /projects/search` — the serving gate, party shaping and contact suppression apply at read time, so a record that has become unservable is dropped from the page rather than served because someone once saved it.\n\n**Charged at read time, unlike alert matches.** An alert's matches were billed when the run materialised them; a list has no run, so this read is the delivery: **1 credit per record**, with a record your account has already received on any surface, unchanged since, **free**. Preflight it free with `GET /lists/{listId}` (`results.billable.credits`). If the page cannot be afforded, nothing is delivered and the `402` carries a quote and that free `countUrl`. `Idempotency-Key` is honoured: a keyed retry replays the same records instead of re-charging.\n\nFor a `filter`/`polygon` list this returns the stored `criteria` plus `links.search`, free — running the search happens on the priced search route.",
                "parameters": [
                    {
                        "name": "listId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "Records per page. Capped at 25 when `representation=full`, which carries the raw source text.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The delivered records, each with a `delivery` block (`alreadyExported`, `updatedSinceExport`, `billed`). `meta.creditsUsed` is what this page actually charged; `meta.total` is the whole list.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "An unknown representation, or `limit` above 25 with `representation=full`.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "No list your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/reference/statuses": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Status filter tokens — free",
                "description": "Canonical `status` filter values plus display aliases (for example `scheduled` and `approved_with_conditions`) that map onto those buckets. **Free.**",
                "responses": {
                    "200": {
                        "description": "Filterable values, aliases with `mapsTo`, and unproducible tokens with reasons.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/reference/owner-types": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Owner type filter values — free",
                "description": "Values accepted by the `ownerTypes` filter. **Free.**",
                "responses": {
                    "200": {
                        "description": "Owner type catalogue.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/reference/decision-bodies": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Decision body filter values — free",
                "description": "Values accepted by the `decisionBodies` filter, including the published other/unknown sentinels. **Free.**",
                "responses": {
                    "200": {
                        "description": "Decision body catalogue.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/reference/request-types": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Request type filter values — free",
                "description": "Values accepted by the `requestTypes` filter. **Free.**",
                "responses": {
                    "200": {
                        "description": "Request type catalogue.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/exports": {
            "get": {
                "tags": [
                    "Exports"
                ],
                "summary": "List export jobs — free",
                "description": "Team export history, including jobs queued via `GET /projects/search?format=csv`. **Free to list.** Credits were reserved when each job was created.",
                "parameters": [
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Recent export jobs for your team scope.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    }
                }
            }
        },
        "/exports/{id}": {
            "get": {
                "tags": [
                    "Exports"
                ],
                "summary": "Poll an export job — free",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Job status and download URLs when ready.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CsvExportJobAccepted"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No such export job in your team scope.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/exports/{id}/download": {
            "get": {
                "tags": [
                    "Exports"
                ],
                "summary": "Download a ready CSV — free",
                "description": "Streams the product-core CSV artifact when status is ready. **Free re-download.** Returns an error body if the job is still running or the file was purged.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "CSV file body.",
                        "content": {
                            "text/csv": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No such export job, not ready yet, or artifact gone.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Boardwalk API key. Keys you create under Settings → API keys are prefixed `bwk_live_` and read the production corpus against your plan or free-trial balance. `bwk_test_` is reserved for a separate sandbox environment that is not serving data yet. Pre-rename `csk_` keys are accepted indefinitely. Create and rotate keys at https://boardwalkai.com/profile/api."
            }
        },
        "headers": {
            "BoardwalkSchemaVersion": {
                "description": "The date-stamped response contract version. Present on every public v1 response.",
                "schema": {
                    "type": "string",
                    "example": "2026-08-18"
                }
            }
        },
        "parameters": {
            "Representation": {
                "name": "representation",
                "in": "query",
                "required": false,
                "description": "How much of each record to return: `compact`, `standard`, `full`. Each nests inside the next and all three cost the same 1 credit per record. An unrecognised value returns `400` rather than being coerced to the default.",
                "schema": {
                    "type": "string",
                    "enum": [
                        "compact",
                        "standard",
                        "full"
                    ],
                    "default": "standard"
                }
            }
        },
        "schemas": {
            "ProjectRecordCompact": {
                "type": "object",
                "description": "A land use project record at the `compact` representation. Every representation costs the same 1 credit per record. Where our current-generation extraction has not covered an attribute, the field is null rather than filled from an older, less accurate source.",
                "required": [
                    "id",
                    "recordType",
                    "projectName",
                    "boardwalkLink",
                    "mergedFrom",
                    "lastUpdated",
                    "meetingDate",
                    "delivery",
                    "address",
                    "city",
                    "county",
                    "state",
                    "latitude",
                    "longitude",
                    "inOpportunityZone",
                    "inSfha",
                    "propertyType",
                    "propertyTypeLabel",
                    "landUses",
                    "status",
                    "statusLabel"
                ],
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Boardwalk's stable identifier for this project.",
                        "x-group": "identity",
                        "x-csv-field": "project_id"
                    },
                    "recordType": {
                        "type": "string",
                        "description": "What kind of record this is. Always \"project\" today; reserved for future record types.",
                        "x-group": "identity"
                    },
                    "projectName": {
                        "type": "string",
                        "description": "The project's display name.",
                        "x-group": "identity",
                        "x-csv-field": "project_name"
                    },
                    "boardwalkLink": {
                        "type": "string",
                        "format": "uri",
                        "description": "Deep link to this project in the Boardwalk map.",
                        "x-group": "identity",
                        "x-csv-field": "boardwalk_link"
                    },
                    "mergedFrom": {
                        "type": "array",
                        "description": "The project ids folded into this record as duplicates of the same development, including its own. You are billed once for the record, not once per id.",
                        "x-group": "identity",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "lastUpdated": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When this project record last changed, RFC 3339 UTC.",
                        "x-group": "identity",
                        "x-csv-field": "last_updated"
                    },
                    "meetingDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "The date of the most recent public meeting this project appeared at.",
                        "x-group": "identity",
                        "x-csv-field": "meeting_date"
                    },
                    "delivery": {
                        "nullable": true,
                        "description": "What Boardwalk has already delivered to your credit pool for this record, and whether this delivery was billed. GET /projects/sync returns these same four keys plus a change payload (what moved, and which new filing caused it) — see the SyncDeliveryState schema.",
                        "x-group": "delivery",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DeliveryState"
                            }
                        ]
                    },
                    "address": {
                        "type": "string",
                        "nullable": true,
                        "description": "The project's street address as stated in the public filing.",
                        "x-group": "location",
                        "x-csv-field": "address"
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "description": "City the project is in.",
                        "x-group": "location",
                        "x-csv-field": "city"
                    },
                    "county": {
                        "type": "string",
                        "nullable": true,
                        "description": "County the project is in.",
                        "x-group": "location",
                        "x-csv-field": "county"
                    },
                    "state": {
                        "type": "string",
                        "nullable": true,
                        "description": "Two-letter state code.",
                        "x-group": "location",
                        "x-csv-field": "state"
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Latitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Longitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "inOpportunityZone": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a federal Opportunity Zone (2018 designation). Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "inSfha": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "propertyType": {
                        "type": "string",
                        "nullable": true,
                        "description": "Top-level land-use classification, e.g. residential.",
                        "x-group": "classification",
                        "x-csv-field": "property_type"
                    },
                    "propertyTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of propertyType.",
                        "x-group": "classification"
                    },
                    "landUses": {
                        "type": "array",
                        "description": "Every land use on this project, to the deepest level we know for each — a mixed-use development lists all of them. `assetClass` is null on an entry where the record only told us the type and subtype; we never copy a parent value down. One use is listed once: where the source describes the same use twice and one description stops short of the other, only the fuller one is listed. `matchedOn` names which taxonomy levels of that use satisfied your filter — `[\"subtype\"]`, `[\"subtype\",\"assetClass\"]` — so you can see why the project is in your results; it is an empty list on uses that did not match and on every use when you filtered on no taxonomy at all. Procedural items such as rezones are not land uses and appear as requestType instead.",
                        "x-group": "classification",
                        "items": {
                            "$ref": "#/components/schemas/ProjectLandUse"
                        }
                    },
                    "matchRole": {
                        "type": "string",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`, which covers all three taxonomy levels rather than asset class alone. When an assetClasses filter is active: `primary` if the project's primary asset class matched, `secondary` if only another classification did. Absent when no asset-class filter was applied.",
                        "x-group": "classification"
                    },
                    "matchedClassification": {
                        "type": "object",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`. The classification that satisfied the active assetClasses filter (often not the primary one). Absent when no asset-class filter was applied. Primary taxonomy fields stay the project's primary.",
                        "x-group": "classification",
                        "required": [
                            "role",
                            "type",
                            "typeLabel",
                            "subtype",
                            "subtypeLabel",
                            "assetClass",
                            "assetClassLabel"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "role": {
                                "type": "string",
                                "nullable": true
                            },
                            "type": {
                                "type": "string",
                                "nullable": true
                            },
                            "typeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtype": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtypeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClass": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClassLabel": {
                                "type": "string",
                                "nullable": true
                            }
                        },
                        "title": "Matched Classification"
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "Where this project stands, as a stable machine token.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    },
                    "statusLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of status; identical to the CSV's Current Status cell.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    }
                }
            },
            "ProjectRecord": {
                "type": "object",
                "description": "A land use project record at the `standard` representation. Every representation costs the same 1 credit per record. Where our current-generation extraction has not covered an attribute, the field is null rather than filled from an older, less accurate source.",
                "required": [
                    "id",
                    "recordType",
                    "projectName",
                    "projectHeadline",
                    "boardwalkLink",
                    "mergedFrom",
                    "lastUpdated",
                    "meetingDate",
                    "delivery",
                    "address",
                    "city",
                    "county",
                    "state",
                    "postalCode",
                    "latitude",
                    "longitude",
                    "locationPrecision",
                    "locationPrecisionLabel",
                    "isApproximate",
                    "parcelApn",
                    "inOpportunityZone",
                    "inSfha",
                    "propertyType",
                    "propertyTypeLabel",
                    "propertySubtype",
                    "propertySubtypeLabel",
                    "assetClass",
                    "assetClassLabel",
                    "landUses",
                    "status",
                    "statusLabel",
                    "statusDetail",
                    "requestType",
                    "requestTypeLabel",
                    "decisionBody",
                    "caseNumbers",
                    "acreage",
                    "squareFootage",
                    "unitCount",
                    "totalUnitCount",
                    "bedroomCount",
                    "buildingStories",
                    "floorCount",
                    "buildingHeightFeet",
                    "parkingSpaces",
                    "existingZoning",
                    "proposedZoning",
                    "isRezone",
                    "constructionType",
                    "constructionTypeLabel",
                    "ownerType",
                    "ownerTypeLabel",
                    "constructionDescription",
                    "developerCompany",
                    "developerCompanyRole",
                    "developerCompanyRoleLabel",
                    "contacts",
                    "contactEnrichment",
                    "companyEnrichment",
                    "publicOfficials",
                    "contactSummary",
                    "keyFacts",
                    "evidence",
                    "voteSummary"
                ],
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Boardwalk's stable identifier for this project.",
                        "x-group": "identity",
                        "x-csv-field": "project_id"
                    },
                    "recordType": {
                        "type": "string",
                        "description": "What kind of record this is. Always \"project\" today; reserved for future record types.",
                        "x-group": "identity"
                    },
                    "projectName": {
                        "type": "string",
                        "description": "The project's display name.",
                        "x-group": "identity",
                        "x-csv-field": "project_name"
                    },
                    "projectHeadline": {
                        "type": "string",
                        "nullable": true,
                        "description": "A one-line description of the latest development on this project.",
                        "x-group": "identity",
                        "x-csv-field": "project_headline"
                    },
                    "boardwalkLink": {
                        "type": "string",
                        "format": "uri",
                        "description": "Deep link to this project in the Boardwalk map.",
                        "x-group": "identity",
                        "x-csv-field": "boardwalk_link"
                    },
                    "mergedFrom": {
                        "type": "array",
                        "description": "The project ids folded into this record as duplicates of the same development, including its own. You are billed once for the record, not once per id.",
                        "x-group": "identity",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "lastUpdated": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When this project record last changed, RFC 3339 UTC.",
                        "x-group": "identity",
                        "x-csv-field": "last_updated"
                    },
                    "meetingDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "The date of the most recent public meeting this project appeared at.",
                        "x-group": "identity",
                        "x-csv-field": "meeting_date"
                    },
                    "delivery": {
                        "nullable": true,
                        "description": "What Boardwalk has already delivered to your credit pool for this record, and whether this delivery was billed. GET /projects/sync returns these same four keys plus a change payload (what moved, and which new filing caused it) — see the SyncDeliveryState schema.",
                        "x-group": "delivery",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DeliveryState"
                            }
                        ]
                    },
                    "address": {
                        "type": "string",
                        "nullable": true,
                        "description": "The project's street address as stated in the public filing.",
                        "x-group": "location",
                        "x-csv-field": "address"
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "description": "City the project is in.",
                        "x-group": "location",
                        "x-csv-field": "city"
                    },
                    "county": {
                        "type": "string",
                        "nullable": true,
                        "description": "County the project is in.",
                        "x-group": "location",
                        "x-csv-field": "county"
                    },
                    "state": {
                        "type": "string",
                        "nullable": true,
                        "description": "Two-letter state code.",
                        "x-group": "location",
                        "x-csv-field": "state"
                    },
                    "postalCode": {
                        "type": "string",
                        "nullable": true,
                        "description": "Postal code of the project's primary address.",
                        "x-group": "location"
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Latitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Longitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "locationPrecision": {
                        "type": "string",
                        "nullable": true,
                        "description": "How precisely this project is placed: address, parcel, location_description, city or county.",
                        "x-group": "location"
                    },
                    "locationPrecisionLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of locationPrecision.",
                        "x-group": "location"
                    },
                    "isApproximate": {
                        "type": "boolean",
                        "description": "True when the coordinates are inferred rather than taken from a street address.",
                        "x-group": "location"
                    },
                    "parcelApn": {
                        "type": "array",
                        "description": "Assessor parcel numbers named in the filing.",
                        "x-group": "location",
                        "x-csv-field": "parcel_apn",
                        "items": {
                            "type": "string"
                        }
                    },
                    "inOpportunityZone": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a federal Opportunity Zone (2018 designation). Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "inSfha": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "propertyType": {
                        "type": "string",
                        "nullable": true,
                        "description": "Top-level land-use classification, e.g. residential.",
                        "x-group": "classification",
                        "x-csv-field": "property_type"
                    },
                    "propertyTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of propertyType.",
                        "x-group": "classification"
                    },
                    "propertySubtype": {
                        "type": "string",
                        "nullable": true,
                        "description": "Second-level land-use classification, e.g. multifamily.",
                        "x-group": "classification",
                        "x-csv-field": "property_subtype"
                    },
                    "propertySubtypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of propertySubtype.",
                        "x-group": "classification"
                    },
                    "assetClass": {
                        "type": "string",
                        "nullable": true,
                        "description": "Third-level land-use classification for the project's headline use, e.g. apartments — the first one we know where that use stops short of this level. Blank means the project has no asset class recorded at all; see `landUses` for every use it does have. Never a duplicated parent value.",
                        "x-group": "classification",
                        "x-csv-field": "asset_class"
                    },
                    "assetClassLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of assetClass.",
                        "x-group": "classification"
                    },
                    "landUses": {
                        "type": "array",
                        "description": "Every land use on this project, to the deepest level we know for each — a mixed-use development lists all of them. `assetClass` is null on an entry where the record only told us the type and subtype; we never copy a parent value down. One use is listed once: where the source describes the same use twice and one description stops short of the other, only the fuller one is listed. `matchedOn` names which taxonomy levels of that use satisfied your filter — `[\"subtype\"]`, `[\"subtype\",\"assetClass\"]` — so you can see why the project is in your results; it is an empty list on uses that did not match and on every use when you filtered on no taxonomy at all. Procedural items such as rezones are not land uses and appear as requestType instead.",
                        "x-group": "classification",
                        "items": {
                            "$ref": "#/components/schemas/ProjectLandUse"
                        }
                    },
                    "matchRole": {
                        "type": "string",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`, which covers all three taxonomy levels rather than asset class alone. When an assetClasses filter is active: `primary` if the project's primary asset class matched, `secondary` if only another classification did. Absent when no asset-class filter was applied.",
                        "x-group": "classification"
                    },
                    "matchedClassification": {
                        "type": "object",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`. The classification that satisfied the active assetClasses filter (often not the primary one). Absent when no asset-class filter was applied. Primary taxonomy fields stay the project's primary.",
                        "x-group": "classification",
                        "required": [
                            "role",
                            "type",
                            "typeLabel",
                            "subtype",
                            "subtypeLabel",
                            "assetClass",
                            "assetClassLabel"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "role": {
                                "type": "string",
                                "nullable": true
                            },
                            "type": {
                                "type": "string",
                                "nullable": true
                            },
                            "typeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtype": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtypeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClass": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClassLabel": {
                                "type": "string",
                                "nullable": true
                            }
                        },
                        "title": "Matched Classification"
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "Where this project stands, as a stable machine token.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    },
                    "statusLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of status; identical to the CSV's Current Status cell.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    },
                    "statusDetail": {
                        "type": "string",
                        "nullable": true,
                        "description": "A sentence expanding on the current status.",
                        "x-group": "status",
                        "x-csv-field": "status_detail"
                    },
                    "requestType": {
                        "type": "string",
                        "nullable": true,
                        "description": "What the applicant asked the jurisdiction for, as a stable machine token.",
                        "x-group": "status",
                        "x-csv-field": "request_type"
                    },
                    "requestTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of requestType.",
                        "x-group": "status",
                        "x-csv-field": "request_type"
                    },
                    "decisionBody": {
                        "type": "string",
                        "nullable": true,
                        "description": "The body that heard or decided the request, e.g. Planning Commission.",
                        "x-group": "status",
                        "x-csv-field": "decision_body"
                    },
                    "caseNumbers": {
                        "type": "array",
                        "description": "Jurisdiction case numbers for this project.",
                        "x-group": "status",
                        "x-csv-field": "case_number",
                        "items": {
                            "type": "string"
                        }
                    },
                    "acreage": {
                        "type": "number",
                        "nullable": true,
                        "description": "Total site area in acres.",
                        "x-group": "site",
                        "x-unit": "acres",
                        "x-csv-field": "acreage"
                    },
                    "squareFootage": {
                        "type": "number",
                        "nullable": true,
                        "description": "Total gross building floor area explicitly stated across building or use rows.",
                        "x-group": "site",
                        "x-unit": "sqft"
                    },
                    "unitCount": {
                        "type": "array",
                        "description": "Dwelling or space counts by type. Entry N's count always describes entry N's type.",
                        "x-group": "site",
                        "x-unit": "count",
                        "x-csv-field": "unit_count",
                        "items": {
                            "$ref": "#/components/schemas/UnitCount"
                        }
                    },
                    "totalUnitCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Total dwelling units across all unit types.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "bedroomCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Total bedrooms across the project.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "buildingStories": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Number of storeys.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "floorCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Highest stated above-grade story count among explicit building rows.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "buildingHeightFeet": {
                        "type": "number",
                        "nullable": true,
                        "description": "Building height in feet. Null where the filing stated a height whose unit we cannot resolve — we do not guess.",
                        "x-group": "site",
                        "x-unit": "feet"
                    },
                    "parkingSpaces": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Parking spaces proposed.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "existingZoning": {
                        "type": "string",
                        "nullable": true,
                        "description": "The site's zoning code before the request.",
                        "x-group": "zoning",
                        "x-csv-field": "existing_zoning"
                    },
                    "proposedZoning": {
                        "type": "string",
                        "nullable": true,
                        "description": "The zoning code being requested.",
                        "x-group": "zoning",
                        "x-csv-field": "proposed_zoning"
                    },
                    "isRezone": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "True when the request changes the site's zoning. Null means unknown, never false.",
                        "x-group": "zoning",
                        "x-csv-field": "is_rezone"
                    },
                    "constructionType": {
                        "type": "string",
                        "nullable": true,
                        "description": "The kind of construction work proposed, as a stable machine token.",
                        "x-group": "construction",
                        "x-csv-field": "construction_type"
                    },
                    "constructionTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of constructionType.",
                        "x-group": "construction",
                        "x-csv-field": "construction_type"
                    },
                    "ownerType": {
                        "type": "string",
                        "nullable": true,
                        "description": "Whether the owner is public, private or institutional, as a stable machine token.",
                        "x-group": "construction",
                        "x-csv-field": "owner_type"
                    },
                    "ownerTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of ownerType.",
                        "x-group": "construction",
                        "x-csv-field": "owner_type"
                    },
                    "constructionDescription": {
                        "type": "string",
                        "nullable": true,
                        "description": "A short sourced description of the construction work, written for business development.",
                        "x-group": "construction"
                    },
                    "developerCompany": {
                        "type": "string",
                        "nullable": true,
                        "description": "The external company developing or applying for this project. Government entities never appear here, even when the filing names one as the applicant.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company"
                    },
                    "developerCompanyRole": {
                        "type": "string",
                        "nullable": true,
                        "description": "How the developer company is named in the filing: developer, builder or applicant.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company_role"
                    },
                    "developerCompanyRoleLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of developerCompanyRole.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company_role"
                    },
                    "contacts": {
                        "type": "array",
                        "description": "External parties on this project — developer, applicant, architect, engineer, contractor, owner. Contact channels are included on paid plans; on a free trial they are null and contactsWithheldReason says why.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/Contact"
                        }
                    },
                    "contactEnrichment": {
                        "type": "object",
                        "description": "What happened when we tried to enrich this record's contacts. status is not_requested unless the request set include=contacts. Enrichment never changes what a record costs: every record is 1 credit whether enrichment found somebody, found nobody, or was never attempted — so a blank contact block always says which of those it was.",
                        "x-group": "contacts",
                        "required": [
                            "status",
                            "statusLabel",
                            "attemptedAt",
                            "contactsFound",
                            "source"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "status": {
                                "type": "string",
                                "nullable": true
                            },
                            "statusLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "attemptedAt": {
                                "type": "string",
                                "nullable": true
                            },
                            "contactsFound": {
                                "type": "integer",
                                "nullable": true
                            },
                            "source": {
                                "type": "string",
                                "nullable": true
                            }
                        },
                        "title": "Contact Enrichment"
                    },
                    "companyEnrichment": {
                        "type": "array",
                        "description": "Companies on this project resolved against Boardwalk's company registry: official name, website, LinkedIn page, archetype and main phone. Names and websites are included on every plan — they are corporate facts, not personal data. The remaining keys are null outside a paid plan, and the array is empty unless the request set include=contacts.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/EnrichedCompany"
                        }
                    },
                    "publicOfficials": {
                        "type": "array",
                        "description": "Government staff and elected officials named in the public record. Their names, roles and votes are public-record facts. Boardwalk never distributes their personal contact details, on any plan.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/PublicOfficial"
                        }
                    },
                    "contactSummary": {
                        "description": "externalCount is the number of entries in contacts[]; governmentCount the number in publicOfficials[]; unclassifiedCount the parties — people or companies — the filing did not identify clearly enough for us to place in either, which are therefore in neither. withheldCount and withheldReason say how many contact channels were withheld and why. lowConfidenceWithheld counts contacts we hold but do not publish because the evidence for them is only pattern-inferred or uncorroborated — a blank there is a decision, not a gap in coverage.",
                        "x-group": "contacts",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/ContactSummary"
                            }
                        ]
                    },
                    "keyFacts": {
                        "type": "array",
                        "description": "Discrete facts extracted from the filing, each with the category it belongs to.",
                        "x-group": "evidence",
                        "x-csv-field": "key_facts",
                        "items": {
                            "$ref": "#/components/schemas/KeyFact"
                        }
                    },
                    "evidence": {
                        "type": "string",
                        "nullable": true,
                        "description": "The passage of the public record that supports the current status.",
                        "x-group": "evidence",
                        "x-csv-field": "evidence"
                    },
                    "alertMatch": {
                        "nullable": true,
                        "description": "Why this record matched the alert that delivered it. Absent on ordinary searches.",
                        "x-group": "alertMatch",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AlertMatch"
                            }
                        ]
                    },
                    "aiMatch": {
                        "nullable": true,
                        "description": "Why the AI search matched this record, and how strongly. Absent on structured searches, which do not rank.",
                        "x-group": "alertMatch",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AiMatch"
                            }
                        ]
                    },
                    "voteSummary": {
                        "nullable": true,
                        "description": "The tally of the most recent recorded vote on this project: yes, no, abstain, absent, total, and whether it was unanimous.",
                        "x-group": "decisions",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/VoteSummary"
                            }
                        ]
                    }
                }
            },
            "ProjectRecordFull": {
                "type": "object",
                "description": "A land use project record at the `full` representation. Every representation costs the same 1 credit per record. Where our current-generation extraction has not covered an attribute, the field is null rather than filled from an older, less accurate source.",
                "required": [
                    "id",
                    "recordType",
                    "projectName",
                    "projectHeadline",
                    "boardwalkLink",
                    "mergedFrom",
                    "lastUpdated",
                    "meetingDate",
                    "delivery",
                    "address",
                    "city",
                    "county",
                    "state",
                    "postalCode",
                    "latitude",
                    "longitude",
                    "locationPrecision",
                    "locationPrecisionLabel",
                    "isApproximate",
                    "parcelApn",
                    "stateId",
                    "countyId",
                    "cityId",
                    "additionalAddresses",
                    "inOpportunityZone",
                    "inSfha",
                    "propertyType",
                    "propertyTypeLabel",
                    "propertySubtype",
                    "propertySubtypeLabel",
                    "assetClass",
                    "assetClassLabel",
                    "landUses",
                    "classifications",
                    "tags",
                    "status",
                    "statusLabel",
                    "statusDetail",
                    "requestType",
                    "requestTypeLabel",
                    "decisionBody",
                    "caseNumbers",
                    "isAppeal",
                    "nextHearingDate",
                    "acreage",
                    "squareFootage",
                    "unitCount",
                    "totalUnitCount",
                    "affordableUnits",
                    "bedroomCount",
                    "lotCount",
                    "buildingCount",
                    "buildingStories",
                    "floorCount",
                    "buildingHeightFeet",
                    "parkingSpaces",
                    "densityPerAcre",
                    "amenities",
                    "existingZoning",
                    "proposedZoning",
                    "isRezone",
                    "variancesRequested",
                    "constructionType",
                    "constructionTypeLabel",
                    "ownerType",
                    "ownerTypeLabel",
                    "constructionDescription",
                    "likelyTrades",
                    "estimateEligible",
                    "developerCompany",
                    "developerCompanyRole",
                    "developerCompanyRoleLabel",
                    "contacts",
                    "contactEnrichment",
                    "companyEnrichment",
                    "publicOfficials",
                    "contactSummary",
                    "keyFacts",
                    "evidence",
                    "conditionsOfApproval",
                    "summary",
                    "extendedSummary",
                    "decisions",
                    "voteSummary",
                    "documents"
                ],
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Boardwalk's stable identifier for this project.",
                        "x-group": "identity",
                        "x-csv-field": "project_id"
                    },
                    "recordType": {
                        "type": "string",
                        "description": "What kind of record this is. Always \"project\" today; reserved for future record types.",
                        "x-group": "identity"
                    },
                    "projectName": {
                        "type": "string",
                        "description": "The project's display name.",
                        "x-group": "identity",
                        "x-csv-field": "project_name"
                    },
                    "projectHeadline": {
                        "type": "string",
                        "nullable": true,
                        "description": "A one-line description of the latest development on this project.",
                        "x-group": "identity",
                        "x-csv-field": "project_headline"
                    },
                    "boardwalkLink": {
                        "type": "string",
                        "format": "uri",
                        "description": "Deep link to this project in the Boardwalk map.",
                        "x-group": "identity",
                        "x-csv-field": "boardwalk_link"
                    },
                    "mergedFrom": {
                        "type": "array",
                        "description": "The project ids folded into this record as duplicates of the same development, including its own. You are billed once for the record, not once per id.",
                        "x-group": "identity",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "lastUpdated": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When this project record last changed, RFC 3339 UTC.",
                        "x-group": "identity",
                        "x-csv-field": "last_updated"
                    },
                    "meetingDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "The date of the most recent public meeting this project appeared at.",
                        "x-group": "identity",
                        "x-csv-field": "meeting_date"
                    },
                    "delivery": {
                        "nullable": true,
                        "description": "What Boardwalk has already delivered to your credit pool for this record, and whether this delivery was billed. GET /projects/sync returns these same four keys plus a change payload (what moved, and which new filing caused it) — see the SyncDeliveryState schema.",
                        "x-group": "delivery",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DeliveryState"
                            }
                        ]
                    },
                    "address": {
                        "type": "string",
                        "nullable": true,
                        "description": "The project's street address as stated in the public filing.",
                        "x-group": "location",
                        "x-csv-field": "address"
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "description": "City the project is in.",
                        "x-group": "location",
                        "x-csv-field": "city"
                    },
                    "county": {
                        "type": "string",
                        "nullable": true,
                        "description": "County the project is in.",
                        "x-group": "location",
                        "x-csv-field": "county"
                    },
                    "state": {
                        "type": "string",
                        "nullable": true,
                        "description": "Two-letter state code.",
                        "x-group": "location",
                        "x-csv-field": "state"
                    },
                    "postalCode": {
                        "type": "string",
                        "nullable": true,
                        "description": "Postal code of the project's primary address.",
                        "x-group": "location"
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Latitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true,
                        "description": "Longitude of the project's mapped location.",
                        "x-group": "location"
                    },
                    "locationPrecision": {
                        "type": "string",
                        "nullable": true,
                        "description": "How precisely this project is placed: address, parcel, location_description, city or county.",
                        "x-group": "location"
                    },
                    "locationPrecisionLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of locationPrecision.",
                        "x-group": "location"
                    },
                    "isApproximate": {
                        "type": "boolean",
                        "description": "True when the coordinates are inferred rather than taken from a street address.",
                        "x-group": "location"
                    },
                    "parcelApn": {
                        "type": "array",
                        "description": "Assessor parcel numbers named in the filing.",
                        "x-group": "location",
                        "x-csv-field": "parcel_apn",
                        "items": {
                            "type": "string"
                        }
                    },
                    "stateId": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Boardwalk id of the state, for use with /locations/*.",
                        "x-group": "location"
                    },
                    "countyId": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Boardwalk id of the county, for use with /locations/*.",
                        "x-group": "location"
                    },
                    "cityId": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Boardwalk id of the city, for use with /locations/*.",
                        "x-group": "location"
                    },
                    "additionalAddresses": {
                        "type": "array",
                        "description": "Other addresses associated with this project.",
                        "x-group": "location",
                        "items": {
                            "$ref": "#/components/schemas/ProjectAddress"
                        }
                    },
                    "inOpportunityZone": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a federal Opportunity Zone (2018 designation). Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "inSfha": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether the site is inside a FEMA Special Flood Hazard Area — the 1%-annual-chance regulatory flood zone. Null means membership has not been computed, never false.",
                        "x-group": "location"
                    },
                    "propertyType": {
                        "type": "string",
                        "nullable": true,
                        "description": "Top-level land-use classification, e.g. residential.",
                        "x-group": "classification",
                        "x-csv-field": "property_type"
                    },
                    "propertyTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of propertyType.",
                        "x-group": "classification"
                    },
                    "propertySubtype": {
                        "type": "string",
                        "nullable": true,
                        "description": "Second-level land-use classification, e.g. multifamily.",
                        "x-group": "classification",
                        "x-csv-field": "property_subtype"
                    },
                    "propertySubtypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of propertySubtype.",
                        "x-group": "classification"
                    },
                    "assetClass": {
                        "type": "string",
                        "nullable": true,
                        "description": "Third-level land-use classification for the project's headline use, e.g. apartments — the first one we know where that use stops short of this level. Blank means the project has no asset class recorded at all; see `landUses` for every use it does have. Never a duplicated parent value.",
                        "x-group": "classification",
                        "x-csv-field": "asset_class"
                    },
                    "assetClassLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of assetClass.",
                        "x-group": "classification"
                    },
                    "landUses": {
                        "type": "array",
                        "description": "Every land use on this project, to the deepest level we know for each — a mixed-use development lists all of them. `assetClass` is null on an entry where the record only told us the type and subtype; we never copy a parent value down. One use is listed once: where the source describes the same use twice and one description stops short of the other, only the fuller one is listed. `matchedOn` names which taxonomy levels of that use satisfied your filter — `[\"subtype\"]`, `[\"subtype\",\"assetClass\"]` — so you can see why the project is in your results; it is an empty list on uses that did not match and on every use when you filtered on no taxonomy at all. Procedural items such as rezones are not land uses and appear as requestType instead.",
                        "x-group": "classification",
                        "items": {
                            "$ref": "#/components/schemas/ProjectLandUse"
                        }
                    },
                    "matchRole": {
                        "type": "string",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`, which covers all three taxonomy levels rather than asset class alone. When an assetClasses filter is active: `primary` if the project's primary asset class matched, `secondary` if only another classification did. Absent when no asset-class filter was applied.",
                        "x-group": "classification"
                    },
                    "matchedClassification": {
                        "type": "object",
                        "nullable": true,
                        "description": "Deprecated — use `landUses[].matchedOn`. The classification that satisfied the active assetClasses filter (often not the primary one). Absent when no asset-class filter was applied. Primary taxonomy fields stay the project's primary.",
                        "x-group": "classification",
                        "required": [
                            "role",
                            "type",
                            "typeLabel",
                            "subtype",
                            "subtypeLabel",
                            "assetClass",
                            "assetClassLabel"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "role": {
                                "type": "string",
                                "nullable": true
                            },
                            "type": {
                                "type": "string",
                                "nullable": true
                            },
                            "typeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtype": {
                                "type": "string",
                                "nullable": true
                            },
                            "subtypeLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClass": {
                                "type": "string",
                                "nullable": true
                            },
                            "assetClassLabel": {
                                "type": "string",
                                "nullable": true
                            }
                        },
                        "title": "Matched Classification"
                    },
                    "classifications": {
                        "type": "array",
                        "description": "Every land-use classification on this project, primary and secondary.",
                        "x-group": "classification",
                        "items": {
                            "$ref": "#/components/schemas/ProjectClassification"
                        }
                    },
                    "tags": {
                        "type": "array",
                        "description": "Free-form tags attached to the project.",
                        "x-group": "classification",
                        "items": {
                            "type": "string"
                        }
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "Where this project stands, as a stable machine token.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    },
                    "statusLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of status; identical to the CSV's Current Status cell.",
                        "x-group": "status",
                        "x-csv-field": "current_status"
                    },
                    "statusDetail": {
                        "type": "string",
                        "nullable": true,
                        "description": "A sentence expanding on the current status.",
                        "x-group": "status",
                        "x-csv-field": "status_detail"
                    },
                    "requestType": {
                        "type": "string",
                        "nullable": true,
                        "description": "What the applicant asked the jurisdiction for, as a stable machine token.",
                        "x-group": "status",
                        "x-csv-field": "request_type"
                    },
                    "requestTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of requestType.",
                        "x-group": "status",
                        "x-csv-field": "request_type"
                    },
                    "decisionBody": {
                        "type": "string",
                        "nullable": true,
                        "description": "The body that heard or decided the request, e.g. Planning Commission.",
                        "x-group": "status",
                        "x-csv-field": "decision_body"
                    },
                    "caseNumbers": {
                        "type": "array",
                        "description": "Jurisdiction case numbers for this project.",
                        "x-group": "status",
                        "x-csv-field": "case_number",
                        "items": {
                            "type": "string"
                        }
                    },
                    "isAppeal": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "True when this proceeding is an appeal. Null means unknown, never false.",
                        "x-group": "status"
                    },
                    "nextHearingDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "The next scheduled hearing date, where one was stated.",
                        "x-group": "status",
                        "x-csv-field": "next_hearing_date"
                    },
                    "acreage": {
                        "type": "number",
                        "nullable": true,
                        "description": "Total site area in acres.",
                        "x-group": "site",
                        "x-unit": "acres",
                        "x-csv-field": "acreage"
                    },
                    "squareFootage": {
                        "type": "number",
                        "nullable": true,
                        "description": "Total gross building floor area explicitly stated across building or use rows.",
                        "x-group": "site",
                        "x-unit": "sqft"
                    },
                    "unitCount": {
                        "type": "array",
                        "description": "Dwelling or space counts by type. Entry N's count always describes entry N's type.",
                        "x-group": "site",
                        "x-unit": "count",
                        "x-csv-field": "unit_count",
                        "items": {
                            "$ref": "#/components/schemas/UnitCount"
                        }
                    },
                    "totalUnitCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Total dwelling units across all unit types.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "affordableUnits": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Units designated affordable.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "bedroomCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Total bedrooms across the project.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "lotCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Number of lots in the subdivision or plat.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "buildingCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Number of buildings proposed.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "buildingStories": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Number of storeys.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "floorCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Highest stated above-grade story count among explicit building rows.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "buildingHeightFeet": {
                        "type": "number",
                        "nullable": true,
                        "description": "Building height in feet. Null where the filing stated a height whose unit we cannot resolve — we do not guess.",
                        "x-group": "site",
                        "x-unit": "feet"
                    },
                    "parkingSpaces": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Parking spaces proposed.",
                        "x-group": "site",
                        "x-unit": "count"
                    },
                    "densityPerAcre": {
                        "type": "number",
                        "nullable": true,
                        "description": "Dwelling units per acre. Null where the filing's density unit is not units/acre.",
                        "x-group": "site",
                        "x-unit": "units_per_acre"
                    },
                    "amenities": {
                        "type": "array",
                        "description": "Amenities named in the filing.",
                        "x-group": "site",
                        "items": {
                            "type": "string"
                        }
                    },
                    "existingZoning": {
                        "type": "string",
                        "nullable": true,
                        "description": "The site's zoning code before the request.",
                        "x-group": "zoning",
                        "x-csv-field": "existing_zoning"
                    },
                    "proposedZoning": {
                        "type": "string",
                        "nullable": true,
                        "description": "The zoning code being requested.",
                        "x-group": "zoning",
                        "x-csv-field": "proposed_zoning"
                    },
                    "isRezone": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "True when the request changes the site's zoning. Null means unknown, never false.",
                        "x-group": "zoning",
                        "x-csv-field": "is_rezone"
                    },
                    "variancesRequested": {
                        "type": "array",
                        "description": "Variances or deviations the applicant asked for.",
                        "x-group": "zoning",
                        "x-csv-field": "variances_requested",
                        "items": {
                            "type": "string"
                        }
                    },
                    "constructionType": {
                        "type": "string",
                        "nullable": true,
                        "description": "The kind of construction work proposed, as a stable machine token.",
                        "x-group": "construction",
                        "x-csv-field": "construction_type"
                    },
                    "constructionTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of constructionType.",
                        "x-group": "construction",
                        "x-csv-field": "construction_type"
                    },
                    "ownerType": {
                        "type": "string",
                        "nullable": true,
                        "description": "Whether the owner is public, private or institutional, as a stable machine token.",
                        "x-group": "construction",
                        "x-csv-field": "owner_type"
                    },
                    "ownerTypeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of ownerType.",
                        "x-group": "construction",
                        "x-csv-field": "owner_type"
                    },
                    "constructionDescription": {
                        "type": "string",
                        "nullable": true,
                        "description": "A short sourced description of the construction work, written for business development.",
                        "x-group": "construction"
                    },
                    "likelyTrades": {
                        "type": "array",
                        "description": "Trades this project is likely to need, with the evidence for each.",
                        "x-group": "construction",
                        "x-csv-field": "likely_trades",
                        "items": {
                            "$ref": "#/components/schemas/LikelyTrade"
                        }
                    },
                    "estimateEligible": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "True when the filing carries enough detail to support a cost estimate.",
                        "x-group": "construction"
                    },
                    "developerCompany": {
                        "type": "string",
                        "nullable": true,
                        "description": "The external company developing or applying for this project. Government entities never appear here, even when the filing names one as the applicant.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company"
                    },
                    "developerCompanyRole": {
                        "type": "string",
                        "nullable": true,
                        "description": "How the developer company is named in the filing: developer, builder or applicant.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company_role"
                    },
                    "developerCompanyRoleLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of developerCompanyRole.",
                        "x-group": "contacts",
                        "x-csv-field": "developer_company_role"
                    },
                    "contacts": {
                        "type": "array",
                        "description": "External parties on this project — developer, applicant, architect, engineer, contractor, owner. Contact channels are included on paid plans; on a free trial they are null and contactsWithheldReason says why.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/Contact"
                        }
                    },
                    "contactEnrichment": {
                        "type": "object",
                        "description": "What happened when we tried to enrich this record's contacts. status is not_requested unless the request set include=contacts. Enrichment never changes what a record costs: every record is 1 credit whether enrichment found somebody, found nobody, or was never attempted — so a blank contact block always says which of those it was.",
                        "x-group": "contacts",
                        "required": [
                            "status",
                            "statusLabel",
                            "attemptedAt",
                            "contactsFound",
                            "source"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "status": {
                                "type": "string",
                                "nullable": true
                            },
                            "statusLabel": {
                                "type": "string",
                                "nullable": true
                            },
                            "attemptedAt": {
                                "type": "string",
                                "nullable": true
                            },
                            "contactsFound": {
                                "type": "integer",
                                "nullable": true
                            },
                            "source": {
                                "type": "string",
                                "nullable": true
                            }
                        },
                        "title": "Contact Enrichment"
                    },
                    "companyEnrichment": {
                        "type": "array",
                        "description": "Companies on this project resolved against Boardwalk's company registry: official name, website, LinkedIn page, archetype and main phone. Names and websites are included on every plan — they are corporate facts, not personal data. The remaining keys are null outside a paid plan, and the array is empty unless the request set include=contacts.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/EnrichedCompany"
                        }
                    },
                    "publicOfficials": {
                        "type": "array",
                        "description": "Government staff and elected officials named in the public record. Their names, roles and votes are public-record facts. Boardwalk never distributes their personal contact details, on any plan.",
                        "x-group": "contacts",
                        "items": {
                            "$ref": "#/components/schemas/PublicOfficial"
                        }
                    },
                    "contactSummary": {
                        "description": "externalCount is the number of entries in contacts[]; governmentCount the number in publicOfficials[]; unclassifiedCount the parties — people or companies — the filing did not identify clearly enough for us to place in either, which are therefore in neither. withheldCount and withheldReason say how many contact channels were withheld and why. lowConfidenceWithheld counts contacts we hold but do not publish because the evidence for them is only pattern-inferred or uncorroborated — a blank there is a decision, not a gap in coverage.",
                        "x-group": "contacts",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/ContactSummary"
                            }
                        ]
                    },
                    "keyFacts": {
                        "type": "array",
                        "description": "Discrete facts extracted from the filing, each with the category it belongs to.",
                        "x-group": "evidence",
                        "x-csv-field": "key_facts",
                        "items": {
                            "$ref": "#/components/schemas/KeyFact"
                        }
                    },
                    "evidence": {
                        "type": "string",
                        "nullable": true,
                        "description": "The passage of the public record that supports the current status.",
                        "x-group": "evidence",
                        "x-csv-field": "evidence"
                    },
                    "conditionsOfApproval": {
                        "type": "array",
                        "description": "Verbatim conditions attached to an approval.",
                        "x-group": "evidence",
                        "items": {
                            "type": "string"
                        }
                    },
                    "summary": {
                        "type": "string",
                        "nullable": true,
                        "description": "A paragraph summarising the project.",
                        "x-group": "evidence"
                    },
                    "extendedSummary": {
                        "type": "string",
                        "nullable": true,
                        "description": "A longer narrative summary.",
                        "x-group": "evidence"
                    },
                    "alertMatch": {
                        "nullable": true,
                        "description": "Why this record matched the alert that delivered it. Absent on ordinary searches.",
                        "x-group": "alertMatch",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AlertMatch"
                            }
                        ]
                    },
                    "aiMatch": {
                        "nullable": true,
                        "description": "Why the AI search matched this record, and how strongly. Absent on structured searches, which do not rank.",
                        "x-group": "alertMatch",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AiMatch"
                            }
                        ]
                    },
                    "decisions": {
                        "type": "array",
                        "description": "Every recorded decision on this project, newest meeting first, with the named votes cast and a derived tally.",
                        "x-group": "decisions",
                        "items": {
                            "$ref": "#/components/schemas/ProjectDecision"
                        }
                    },
                    "voteSummary": {
                        "nullable": true,
                        "description": "The tally of the most recent recorded vote on this project: yes, no, abstain, absent, total, and whether it was unanimous.",
                        "x-group": "decisions",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/VoteSummary"
                            }
                        ]
                    },
                    "documents": {
                        "type": "array",
                        "description": "The public meeting documents this project was extracted from. Pass `meetingDocumentId` to `GET /documents/{id}` to fetch one. rawText is the document's transcribed text and is returned in the full representation only.",
                        "x-group": "documents",
                        "items": {
                            "$ref": "#/components/schemas/DocumentRef"
                        }
                    }
                }
            },
            "AiMatch": {
                "type": "object",
                "title": "AI Match",
                "required": [
                    "score",
                    "summary",
                    "channels"
                ],
                "additionalProperties": false,
                "properties": {
                    "score": {
                        "type": "number",
                        "nullable": true
                    },
                    "summary": {
                        "type": "string",
                        "nullable": true
                    },
                    "channels": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "nullable": true
                    }
                }
            },
            "AlertMatch": {
                "type": "object",
                "title": "Alert Match",
                "required": [
                    "alertName",
                    "why",
                    "quotes"
                ],
                "additionalProperties": false,
                "properties": {
                    "alertName": {
                        "type": "string",
                        "nullable": true
                    },
                    "why": {
                        "type": "string",
                        "nullable": true
                    },
                    "quotes": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "nullable": true
                    }
                }
            },
            "Contact": {
                "type": "object",
                "title": "Contacts",
                "required": [
                    "name",
                    "title",
                    "role",
                    "roleLabel",
                    "partyClass",
                    "partyClassLabel",
                    "entityType",
                    "company",
                    "email",
                    "emailSource",
                    "phone",
                    "phoneSource",
                    "linkedinUrl",
                    "linkedinSource",
                    "contactProvenance",
                    "enrichmentSource",
                    "enrichedAt",
                    "enrichmentStatus",
                    "contactsWithheldReason"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "role": {
                        "type": "string",
                        "nullable": true
                    },
                    "roleLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "partyClass": {
                        "type": "string",
                        "nullable": true
                    },
                    "partyClassLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "entityType": {
                        "type": "string",
                        "nullable": true
                    },
                    "company": {
                        "type": "string",
                        "nullable": true
                    },
                    "email": {
                        "type": "string",
                        "nullable": true
                    },
                    "emailSource": {
                        "type": "string",
                        "nullable": true
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "phoneSource": {
                        "type": "string",
                        "nullable": true
                    },
                    "linkedinUrl": {
                        "type": "string",
                        "nullable": true
                    },
                    "linkedinSource": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactProvenance": {
                        "type": "string",
                        "nullable": true
                    },
                    "enrichmentSource": {
                        "type": "string",
                        "nullable": true
                    },
                    "enrichedAt": {
                        "type": "string",
                        "nullable": true
                    },
                    "enrichmentStatus": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactsWithheldReason": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "ContactSummary": {
                "type": "object",
                "title": "Contact Summary",
                "required": [
                    "externalCount",
                    "governmentCount",
                    "unclassifiedCount",
                    "withEmail",
                    "withPhone",
                    "withLinkedin",
                    "enrichedCount",
                    "lowConfidenceWithheld",
                    "withheldCount",
                    "withheldReason"
                ],
                "additionalProperties": false,
                "properties": {
                    "externalCount": {
                        "type": "integer",
                        "nullable": true
                    },
                    "governmentCount": {
                        "type": "integer",
                        "nullable": true
                    },
                    "unclassifiedCount": {
                        "type": "integer",
                        "nullable": true
                    },
                    "withEmail": {
                        "type": "integer",
                        "nullable": true
                    },
                    "withPhone": {
                        "type": "integer",
                        "nullable": true
                    },
                    "withLinkedin": {
                        "type": "integer",
                        "nullable": true
                    },
                    "enrichedCount": {
                        "type": "integer",
                        "nullable": true
                    },
                    "lowConfidenceWithheld": {
                        "type": "integer",
                        "nullable": true
                    },
                    "withheldCount": {
                        "type": "integer",
                        "nullable": true
                    },
                    "withheldReason": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "DeliveryState": {
                "type": "object",
                "title": "Delivery State",
                "required": [
                    "alreadyExported",
                    "updatedSinceExport",
                    "lastExportedAt",
                    "billed"
                ],
                "additionalProperties": false,
                "properties": {
                    "alreadyExported": {
                        "type": "boolean",
                        "nullable": true
                    },
                    "updatedSinceExport": {
                        "type": "boolean",
                        "nullable": true
                    },
                    "lastExportedAt": {
                        "type": "string",
                        "nullable": true
                    },
                    "billed": {
                        "type": "boolean",
                        "nullable": true
                    }
                }
            },
            "DocumentRef": {
                "type": "object",
                "title": "Documents",
                "required": [
                    "meetingDocumentId",
                    "title",
                    "meetingDate",
                    "documentType",
                    "documentTypeLabel",
                    "rawText",
                    "rawTextTruncated"
                ],
                "additionalProperties": false,
                "properties": {
                    "meetingDocumentId": {
                        "type": "integer",
                        "nullable": true
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "meetingDate": {
                        "type": "string",
                        "nullable": true
                    },
                    "documentType": {
                        "type": "string",
                        "nullable": true
                    },
                    "documentTypeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "rawText": {
                        "type": "string",
                        "nullable": true
                    },
                    "rawTextTruncated": {
                        "type": "boolean",
                        "nullable": true
                    }
                }
            },
            "EnrichedCompany": {
                "type": "object",
                "title": "Company Enrichment",
                "required": [
                    "name",
                    "website",
                    "linkedinUrl",
                    "archetype",
                    "phone"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "website": {
                        "type": "string",
                        "nullable": true
                    },
                    "linkedinUrl": {
                        "type": "string",
                        "nullable": true
                    },
                    "archetype": {
                        "type": "string",
                        "nullable": true
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "KeyFact": {
                "type": "object",
                "title": "Key Facts",
                "required": [
                    "fact",
                    "category",
                    "categoryLabel"
                ],
                "additionalProperties": false,
                "properties": {
                    "fact": {
                        "type": "string",
                        "nullable": true
                    },
                    "category": {
                        "type": "string",
                        "nullable": true
                    },
                    "categoryLabel": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "LikelyTrade": {
                "type": "object",
                "title": "Likely Trades",
                "required": [
                    "trade",
                    "tradeLabel",
                    "basis"
                ],
                "additionalProperties": false,
                "properties": {
                    "trade": {
                        "type": "string",
                        "nullable": true
                    },
                    "tradeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "basis": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "ProjectAddress": {
                "type": "object",
                "title": "Additional Addresses",
                "required": [
                    "address",
                    "city",
                    "state",
                    "postalCode",
                    "latitude",
                    "longitude"
                ],
                "additionalProperties": false,
                "properties": {
                    "address": {
                        "type": "string",
                        "nullable": true
                    },
                    "city": {
                        "type": "string",
                        "nullable": true
                    },
                    "state": {
                        "type": "string",
                        "nullable": true
                    },
                    "postalCode": {
                        "type": "string",
                        "nullable": true
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true
                    }
                }
            },
            "ProjectClassification": {
                "type": "object",
                "title": "All Classifications",
                "required": [
                    "role",
                    "type",
                    "typeLabel",
                    "subtype",
                    "subtypeLabel",
                    "assetClass",
                    "assetClassLabel"
                ],
                "additionalProperties": false,
                "properties": {
                    "role": {
                        "type": "string",
                        "nullable": true
                    },
                    "type": {
                        "type": "string",
                        "nullable": true
                    },
                    "typeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "subtype": {
                        "type": "string",
                        "nullable": true
                    },
                    "subtypeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "assetClass": {
                        "type": "string",
                        "nullable": true
                    },
                    "assetClassLabel": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "ProjectDecision": {
                "type": "object",
                "title": "Decisions",
                "required": [
                    "meetingDate",
                    "decisionBody",
                    "actionType",
                    "actionTypeLabel",
                    "requestType",
                    "requestTypeLabel",
                    "outcome",
                    "outcomeLabel",
                    "motionType",
                    "motionOutcome",
                    "evidenceBasis",
                    "evidenceBasisLabel",
                    "isConsentAgenda",
                    "caseNumber",
                    "evidence",
                    "conditions",
                    "voteTally",
                    "votes"
                ],
                "additionalProperties": false,
                "properties": {
                    "meetingDate": {
                        "type": "string",
                        "nullable": true
                    },
                    "decisionBody": {
                        "type": "string",
                        "nullable": true
                    },
                    "actionType": {
                        "type": "string",
                        "nullable": true
                    },
                    "actionTypeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "requestType": {
                        "type": "string",
                        "nullable": true
                    },
                    "requestTypeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "outcome": {
                        "type": "string",
                        "nullable": true
                    },
                    "outcomeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "motionType": {
                        "type": "string",
                        "nullable": true
                    },
                    "motionOutcome": {
                        "type": "string",
                        "nullable": true
                    },
                    "evidenceBasis": {
                        "type": "string",
                        "nullable": true
                    },
                    "evidenceBasisLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "isConsentAgenda": {
                        "type": "boolean",
                        "nullable": true
                    },
                    "caseNumber": {
                        "type": "string",
                        "nullable": true
                    },
                    "evidence": {
                        "type": "string",
                        "nullable": true
                    },
                    "conditions": {
                        "type": "string",
                        "nullable": true
                    },
                    "voteTally": {
                        "nullable": true,
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/VoteTally"
                            }
                        ]
                    },
                    "votes": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Vote"
                        },
                        "nullable": true
                    }
                }
            },
            "ProjectLandUse": {
                "type": "object",
                "title": "Land Uses",
                "required": [
                    "type",
                    "typeLabel",
                    "subtype",
                    "subtypeLabel",
                    "assetClass",
                    "assetClassLabel",
                    "matchedOn"
                ],
                "additionalProperties": false,
                "properties": {
                    "type": {
                        "type": "string",
                        "nullable": true
                    },
                    "typeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "subtype": {
                        "type": "string",
                        "nullable": true
                    },
                    "subtypeLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "assetClass": {
                        "type": "string",
                        "nullable": true
                    },
                    "assetClassLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "matchedOn": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "nullable": true
                    }
                }
            },
            "PublicOfficial": {
                "type": "object",
                "title": "Public Officials",
                "required": [
                    "name",
                    "title",
                    "role",
                    "roleLabel",
                    "partyClass",
                    "organization"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "role": {
                        "type": "string",
                        "nullable": true
                    },
                    "roleLabel": {
                        "type": "string",
                        "nullable": true
                    },
                    "partyClass": {
                        "type": "string",
                        "nullable": true
                    },
                    "organization": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "UnitCount": {
                "type": "object",
                "title": "Unit Count",
                "required": [
                    "count",
                    "type",
                    "typeLabel"
                ],
                "additionalProperties": false,
                "properties": {
                    "count": {
                        "type": "number",
                        "nullable": true
                    },
                    "type": {
                        "type": "string",
                        "nullable": true
                    },
                    "typeLabel": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "Vote": {
                "type": "object",
                "title": "Vote",
                "required": [
                    "name",
                    "role",
                    "vote",
                    "voteLabel"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "role": {
                        "type": "string",
                        "nullable": true
                    },
                    "vote": {
                        "type": "string",
                        "nullable": true
                    },
                    "voteLabel": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "VoteSummary": {
                "type": "object",
                "title": "Vote Summary",
                "required": [
                    "yes",
                    "no",
                    "abstain",
                    "absent",
                    "total",
                    "isUnanimous",
                    "meetingDate"
                ],
                "additionalProperties": false,
                "properties": {
                    "yes": {
                        "type": "integer",
                        "nullable": true
                    },
                    "no": {
                        "type": "integer",
                        "nullable": true
                    },
                    "abstain": {
                        "type": "integer",
                        "nullable": true
                    },
                    "absent": {
                        "type": "integer",
                        "nullable": true
                    },
                    "total": {
                        "type": "integer",
                        "nullable": true
                    },
                    "isUnanimous": {
                        "type": "boolean",
                        "nullable": true
                    },
                    "meetingDate": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "VoteTally": {
                "type": "object",
                "title": "VoteTally",
                "required": [
                    "yes",
                    "no",
                    "abstain",
                    "absent",
                    "total",
                    "isUnanimous"
                ],
                "additionalProperties": false,
                "properties": {
                    "yes": {
                        "type": "integer",
                        "nullable": true
                    },
                    "no": {
                        "type": "integer",
                        "nullable": true
                    },
                    "abstain": {
                        "type": "integer",
                        "nullable": true
                    },
                    "absent": {
                        "type": "integer",
                        "nullable": true
                    },
                    "total": {
                        "type": "integer",
                        "nullable": true
                    },
                    "isUnanimous": {
                        "type": "boolean",
                        "nullable": true
                    }
                }
            },
            "ApiError": {
                "type": "object",
                "required": [
                    "error"
                ],
                "properties": {
                    "error": {
                        "type": "object",
                        "required": [
                            "code",
                            "message",
                            "param",
                            "details",
                            "docsUrl",
                            "requestId"
                        ],
                        "properties": {
                            "code": {
                                "type": "string",
                                "description": "Stable machine-readable code. Branch on this value."
                            },
                            "message": {
                                "type": "string",
                                "description": "Human-readable explanation. Do not parse it."
                            },
                            "param": {
                                "type": "string",
                                "nullable": true,
                                "description": "The offending input parameter, when applicable."
                            },
                            "details": {
                                "type": "object",
                                "description": "Structured, camelCase context. Always an object, empty when there is no context.",
                                "additionalProperties": true
                            },
                            "docsUrl": {
                                "type": "string",
                                "format": "uri",
                                "description": "Documentation for this exact error code."
                            },
                            "requestId": {
                                "type": "string",
                                "description": "Matches X-Request-Id and the server-side usage/log record."
                            }
                        },
                        "additionalProperties": false
                    }
                },
                "additionalProperties": false
            },
            "PaginationMeta": {
                "type": "object",
                "properties": {
                    "schemaVersion": {
                        "type": "string",
                        "description": "The response-contract version this payload was built against. Also sent as the `X-Boardwalk-Schema-Version` header. Pin it and diff it.",
                        "example": "2026-08-18"
                    },
                    "representation": {
                        "type": "string",
                        "enum": [
                            "compact",
                            "standard",
                            "full"
                        ],
                        "description": "Echoed back, so a client can assert it received the shape it asked for."
                    },
                    "total": {
                        "type": "integer",
                        "deprecated": true,
                        "description": "Legacy page-progress value: offset plus records returned on this page. It is not a match total. Use pageCount/hasMore for paging and GET /projects/count for an exact total."
                    },
                    "pageCount": {
                        "type": "integer",
                        "description": "Records returned in data on this page."
                    },
                    "hasMore": {
                        "type": "boolean",
                        "description": "Whether another offset page is retrievable from this bounded scan."
                    },
                    "limit": {
                        "type": "integer"
                    },
                    "offset": {
                        "type": "integer"
                    },
                    "creditsUsed": {
                        "type": "integer",
                        "description": "Credits deducted for this request."
                    },
                    "creditsRemaining": {
                        "type": "integer",
                        "description": "Credits remaining in the current billing period."
                    },
                    "trialTruncation": {
                        "$ref": "#/components/schemas/TrialTruncation"
                    },
                    "searchMethod": {
                        "type": "string",
                        "description": "Which backend served the request (`redisearch`, `ai_multi_signal`, etc.)."
                    },
                    "appliedFilters": {
                        "type": "object",
                        "additionalProperties": true,
                        "description": "Canonical, resolved filters that actually ran."
                    },
                    "appliedDefaults": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Defaults the server applied because the caller omitted them."
                    },
                    "resolvedFrom": {
                        "type": "object",
                        "additionalProperties": true,
                        "description": "Human-readable location inputs and the IDs they resolved to."
                    },
                    "warnings": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "additionalProperties": true
                        },
                        "description": "Machine-readable disclosures such as a clamped page size or default date window."
                    },
                    "matchCount": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Matches counted by this bounded scan, or null when no count was attempted. Use GET /projects/count for a free exact count."
                    },
                    "matchCountIsExact": {
                        "type": "boolean",
                        "description": "True only when the candidate source was fully enumerated."
                    },
                    "matchCountBasis": {
                        "type": "string",
                        "enum": [
                            "not_computed",
                            "enumerated",
                            "partial_scan",
                            "scan_ceiling_reached"
                        ],
                        "description": "Why matchCount is exact, partial or absent."
                    },
                    "filteredAfterSearch": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Candidates removed by each post-query filter stage; omitted when none were removed."
                    },
                    "duplicatesCollapsed": {
                        "type": "integer",
                        "description": "How many duplicate ids were folded into the returned records. You are billed per record, after this collapse, never per id."
                    },
                    "collapseApplied": {
                        "type": "boolean"
                    },
                    "delivery": {
                        "$ref": "#/components/schemas/DeliveryMeta"
                    },
                    "requestId": {
                        "type": "string",
                        "description": "Matches X-Request-Id and the server-side usage/log record."
                    }
                }
            },
            "AiPaginationMeta": {
                "type": "object",
                "properties": {
                    "schemaVersion": {
                        "type": "string",
                        "description": "The response-contract version. Also sent as the X-Boardwalk-Schema-Version header.",
                        "example": "2026-08-18"
                    },
                    "representation": {
                        "type": "string",
                        "enum": [
                            "compact",
                            "standard",
                            "full"
                        ]
                    },
                    "total": {
                        "type": "integer",
                        "description": "The AI search engine's reported result-set total before page delivery."
                    },
                    "limit": {
                        "type": "integer"
                    },
                    "offset": {
                        "type": "integer"
                    },
                    "pageCount": {
                        "type": "integer",
                        "description": "Records returned on this page after collapse and the serving gate."
                    },
                    "hasMore": {
                        "type": "boolean",
                        "description": "Whether the retrieved eligible candidate pool contains another page."
                    },
                    "filteredAfterSearch": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Candidates removed after ranking; `servingGate`, `hardConstraints`, and `mergeCollapse` candidates never fill a paid page slot."
                    },
                    "creditsUsed": {
                        "type": "integer"
                    },
                    "creditsRemaining": {
                        "type": "integer"
                    },
                    "trialTruncation": {
                        "$ref": "#/components/schemas/TrialTruncation"
                    },
                    "searchMethod": {
                        "type": "string"
                    },
                    "duplicatesCollapsed": {
                        "type": "integer",
                        "description": "Duplicate ids folded together in the bounded ranked candidate pool before paging."
                    },
                    "collapseApplied": {
                        "type": "boolean"
                    },
                    "delivery": {
                        "$ref": "#/components/schemas/DeliveryMeta"
                    },
                    "requestId": {
                        "type": "string"
                    }
                }
            },
            "AiSearchJobMeta": {
                "description": "Completed async AI-search metadata. It extends synchronous AI-search metadata with evidence and screening state.",
                "allOf": [
                    {
                        "$ref": "#/components/schemas/AiPaginationMeta"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "creditsReserved": {
                                "type": "integer"
                            },
                            "parsedQuery": {
                                "type": "object",
                                "additionalProperties": true
                            },
                            "matchesByProjectId": {
                                "type": "object",
                                "additionalProperties": {
                                    "type": "object",
                                    "additionalProperties": true
                                }
                            },
                            "lowConfidence": {
                                "type": "boolean"
                            },
                            "stopReason": {
                                "type": "string"
                            },
                            "candidatesRetrieved": {
                                "type": "integer"
                            },
                            "candidatesScreened": {
                                "type": "integer"
                            },
                            "batchesRun": {
                                "type": "integer"
                            },
                            "screeningCeiling": {
                                "type": "integer"
                            },
                            "screeningCeilingSource": {
                                "type": "string"
                            },
                            "batchSizeYields": {
                                "type": "array",
                                "items": {
                                    "type": "integer"
                                }
                            },
                            "partialReason": {
                                "type": "string",
                                "nullable": true
                            },
                            "matchCount": {
                                "type": "integer",
                                "description": "Verified matches that survived final delivery eligibility and hard-constraint revalidation, before offset."
                            },
                            "matchCountIsExact": {
                                "type": "boolean"
                            },
                            "reusedVerdictCount": {
                                "type": "integer"
                            },
                            "verifierErrorCount": {
                                "type": "integer"
                            },
                            "enrichment": {
                                "type": "object",
                                "additionalProperties": true
                            }
                        }
                    }
                ]
            },
            "DeliveryMeta": {
                "type": "object",
                "description": "What this page cost you, split by delivery history. A record you have already been delivered and that has not changed is returned again without being charged again.",
                "properties": {
                    "mode": {
                        "type": "string"
                    },
                    "notPreviouslyExported": {
                        "type": "integer"
                    },
                    "previouslyExported": {
                        "type": "integer"
                    },
                    "updatedSinceExport": {
                        "type": "integer"
                    },
                    "billed": {
                        "type": "integer",
                        "description": "Records charged for on this response."
                    },
                    "notRebilled": {
                        "type": "integer",
                        "description": "Records returned free because you already had them."
                    },
                    "ledgerApplied": {
                        "type": "boolean"
                    }
                }
            },
            "TrialTruncation": {
                "type": "object",
                "nullable": true,
                "description": "**Free trial only.** Non-null when this page was cut short because the trial's record credits ran out mid-request; `null` on every other response, including every response to a paid key. Paid plans are never partially delivered — a request they cannot cover is refused with `402 insufficient_credits` and returns no records at all. Use this field to tell \"your trial ran out\" apart from \"that is all that matched\".",
                "properties": {
                    "reason": {
                        "type": "string",
                        "enum": [
                            "trial_credit_balance_reached"
                        ],
                        "description": "The only reason a response is ever short of what was asked for."
                    },
                    "deliveredCount": {
                        "type": "integer",
                        "description": "Records actually returned and charged."
                    },
                    "requestedCount": {
                        "type": "integer",
                        "description": "Records that would have been returned with a sufficient balance."
                    },
                    "creditsRemaining": {
                        "type": "integer",
                        "description": "Trial credits left after this request."
                    },
                    "message": {
                        "type": "string",
                        "description": "Human-readable explanation, safe to surface to an end user."
                    }
                }
            },
            "AiSearchRequest": {
                "type": "object",
                "description": "Strict AI-search input. Each individual geography array accepts at most 100 raw items (duplicates count). After deduplication, geography accepts at most 100 unique IDs total across state, county, and city fields, including singular and legacy aliases.",
                "additionalProperties": false,
                "anyOf": [
                    {
                        "required": [
                            "query"
                        ]
                    },
                    {
                        "required": [
                            "q"
                        ]
                    }
                ],
                "properties": {
                    "query": {
                        "type": "string",
                        "minLength": 1,
                        "description": "Natural-language search query."
                    },
                    "q": {
                        "type": "string",
                        "minLength": 1,
                        "description": "Alias for `query` (same vocabulary as structured search)."
                    },
                    "representation": {
                        "type": "string",
                        "enum": [
                            "compact",
                            "standard",
                            "full"
                        ],
                        "default": "standard",
                        "description": "How much of each record to return. All three cost the same 1 credit per record. Also accepted as a `?representation=` query parameter."
                    },
                    "deliveryMode": {
                        "type": "string",
                        "enum": [
                            "all"
                        ],
                        "default": "all",
                        "description": "Only `all` is implemented. Other values return `400` rather than being ignored."
                    },
                    "limit": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 10,
                        "description": "Default is 10. Cap is 100. Prefer a low limit until cost is estimated."
                    },
                    "offset": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 999,
                        "default": 0,
                        "description": "Zero-based offset. The complete result window (`offset + limit`) may not exceed 100 on synchronous AI search or 1,000 on the asynchronous job route."
                    },
                    "sort": {
                        "type": "string",
                        "enum": [
                            "meeting_date",
                            "updated_at",
                            "data_richness"
                        ],
                        "default": "meeting_date"
                    },
                    "order": {
                        "type": "string",
                        "enum": [
                            "asc",
                            "desc"
                        ],
                        "default": "desc"
                    },
                    "stateIds": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Optional state ID filter. Every ID must exist; resolve via `GET /locations/states`."
                    },
                    "stateId": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Optional single state ID."
                    },
                    "state": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Legacy alias for `stateIds` — integer IDs only, not abbreviations."
                    },
                    "countyIds": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Optional county ID filter from `/locations/states/{id}/counties`. Every ID must exist."
                    },
                    "countyId": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Optional single county ID."
                    },
                    "county": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Legacy alias for `countyIds` — integer IDs only, not names."
                    },
                    "cityIds": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Optional city ID filter from nested cities location endpoint. Every ID must exist."
                    },
                    "cityId": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "Optional single city ID."
                    },
                    "city": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Legacy alias for `cityIds` — integer IDs only, not names."
                    },
                    "type": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "Optional land use type filter."
                    },
                    "subtype": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "dateFrom": {
                        "type": "string",
                        "description": "Inclusive lower bound: YYYY, YYYY-MM, YYYY-MM-DD, or RFC3339.",
                        "example": "2025-06"
                    },
                    "dateTo": {
                        "type": "string",
                        "description": "Inclusive upper bound: YYYY, YYYY-MM, YYYY-MM-DD, or RFC3339. Must not precede dateFrom."
                    },
                    "include": {
                        "description": "Opt in to Find Contact Info for the projects this job will return. Paid plans only. Off unless you send it.",
                        "oneOf": [
                            {
                                "type": "string",
                                "enum": [
                                    "contacts"
                                ]
                            },
                            {
                                "type": "array",
                                "items": {
                                    "type": "string",
                                    "enum": [
                                        "contacts"
                                    ]
                                }
                            }
                        ]
                    },
                    "contactOptions": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "minConfidence": {
                                "type": "string",
                                "enum": [
                                    "high",
                                    "medium"
                                ],
                                "default": "medium"
                            },
                            "maxProjects": {
                                "type": "integer",
                                "minimum": 1
                            },
                            "cachedOnly": {
                                "type": "boolean",
                                "default": false
                            },
                            "companyOnly": {
                                "type": "boolean",
                                "default": false
                            }
                        }
                    }
                }
            },
            "AiSearchResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "oneOf": [
                                {
                                    "$ref": "#/components/schemas/ProjectRecordCompact"
                                },
                                {
                                    "$ref": "#/components/schemas/ProjectRecord"
                                },
                                {
                                    "$ref": "#/components/schemas/ProjectRecordFull"
                                }
                            ]
                        }
                    },
                    "meta": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AiPaginationMeta"
                            },
                            {
                                "type": "object",
                                "properties": {
                                    "parsedQuery": {
                                        "type": "object",
                                        "description": "What the LLM parsed out of the natural-language query.",
                                        "properties": {
                                            "structuredFilters": {
                                                "type": "object",
                                                "description": "Filters the AI inferred (state, type, dates, etc.)."
                                            },
                                            "searchKeywords": {
                                                "type": "string",
                                                "description": "Keywords used for BM25 text matching."
                                            },
                                            "semanticQuery": {
                                                "type": "string",
                                                "description": "Text used for vector similarity search."
                                            }
                                        }
                                    }
                                }
                            }
                        ]
                    }
                }
            },
            "AiSearchJobAccepted": {
                "type": "object",
                "properties": {
                    "requestId": {
                        "type": "integer"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "completed",
                            "partial",
                            "failed",
                            "cancelled",
                            "expired"
                        ]
                    },
                    "pollUrl": {
                        "type": "string",
                        "example": "https://api.boardwalkai.com/api/v1/projects/ai-search/jobs/123",
                        "description": "Absolute URL to poll. Use this rather than rebuilding path segments."
                    },
                    "meta": {
                        "type": "object",
                        "properties": {
                            "creditsReserved": {
                                "type": "integer"
                            },
                            "limit": {
                                "type": "integer",
                                "description": "Records this job will reserve credits for and return."
                            },
                            "trialTruncation": {
                                "$ref": "#/components/schemas/TrialTruncation"
                            }
                        }
                    }
                }
            },
            "CsvExportJobAccepted": {
                "type": "object",
                "description": "HTTP 202 body for `GET /projects/search?format=csv`, and the same shape from `GET /exports/{id}`.",
                "properties": {
                    "exportJobId": {
                        "type": "integer"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "ready",
                            "failed",
                            "expired",
                            "no_billable_rows"
                        ]
                    },
                    "format": {
                        "type": "string",
                        "enum": [
                            "csv"
                        ]
                    },
                    "pollUrl": {
                        "type": "string"
                    },
                    "downloadUrl": {
                        "type": "string"
                    },
                    "webExportsUrl": {
                        "type": "string",
                        "description": "Product UI export history for the same team scope."
                    },
                    "job": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "meta": {
                        "type": "object",
                        "properties": {
                            "projectCount": {
                                "type": "integer"
                            },
                            "creditsReserved": {
                                "type": "integer"
                            },
                            "columnGroups": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            },
                            "csvFields": {
                                "type": "string",
                                "example": "product_core"
                            },
                            "enrichmentRequested": {
                                "type": "boolean",
                                "description": "True when this job will run Find Contact Info for the exported project IDs."
                            },
                            "creditsUsed": {
                                "type": "integer"
                            },
                            "downloadable": {
                                "type": "boolean"
                            }
                        }
                    }
                }
            },
            "AiSearchJobStatus": {
                "type": "object",
                "properties": {
                    "requestId": {
                        "type": "integer"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "completed",
                            "partial",
                            "failed",
                            "cancelled",
                            "expired"
                        ]
                    },
                    "creditsReserved": {
                        "type": "integer"
                    },
                    "creditsCharged": {
                        "type": "integer",
                        "nullable": true
                    },
                    "data": {
                        "nullable": true,
                        "description": "Project results when completed or partial; null while queued/running.",
                        "type": "array",
                        "items": {
                            "oneOf": [
                                {
                                    "$ref": "#/components/schemas/ProjectRecordCompact"
                                },
                                {
                                    "$ref": "#/components/schemas/ProjectRecord"
                                },
                                {
                                    "$ref": "#/components/schemas/ProjectRecordFull"
                                }
                            ]
                        }
                    },
                    "meta": {
                        "type": "object",
                        "nullable": true,
                        "description": "Same shape as sync AI search meta when completed, plus matchesByProjectId.",
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AiSearchJobMeta"
                            }
                        ]
                    },
                    "error": {
                        "type": "string",
                        "nullable": true
                    },
                    "progress": {
                        "nullable": true,
                        "type": "object",
                        "description": "Live screening progress while queued or running.",
                        "properties": {
                            "stage": {
                                "type": "string",
                                "enum": [
                                    "queued",
                                    "screening"
                                ]
                            },
                            "candidatesRetrieved": {
                                "type": "integer",
                                "nullable": true
                            },
                            "candidatesScreened": {
                                "type": "integer",
                                "minimum": 0
                            },
                            "batchesRun": {
                                "type": "integer",
                                "minimum": 0
                            },
                            "screeningCeiling": {
                                "type": "integer",
                                "nullable": true
                            },
                            "confirmedSoFar": {
                                "type": "integer",
                                "minimum": 0
                            },
                            "cancelRequested": {
                                "type": "boolean"
                            }
                        }
                    },
                    "stopReason": {
                        "type": "string",
                        "nullable": true
                    },
                    "partialReason": {
                        "type": "string",
                        "nullable": true
                    },
                    "createdAt": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "startedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "completedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "expiresAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "ProjectSearchResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ProjectRecord"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/PaginationMeta"
                    }
                },
                "description": "The `data` items are `ProjectRecord` at the default representation. Ask for `?representation=compact` or `?representation=full` and they are `ProjectRecordCompact` or `ProjectRecordFull` instead — each nests inside the next."
            },
            "ProjectSyncResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "allOf": [
                                {
                                    "$ref": "#/components/schemas/ProjectRecord"
                                },
                                {
                                    "type": "object",
                                    "properties": {
                                        "delivery": {
                                            "$ref": "#/components/schemas/SyncDeliveryState"
                                        }
                                    }
                                }
                            ]
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/SyncMeta"
                    }
                },
                "description": "The same record shapes `/projects/search` returns, with a richer `delivery` block: the four delivery-state keys plus what changed since we last sent you this record."
            },
            "SyncDeliveryState": {
                "type": "object",
                "description": "A superset of `DeliveryState` — the same four keys, plus what changed. The change keys are present on `GET /projects/sync` and absent elsewhere; they are populated only when `updatedSinceExport` is true.",
                "properties": {
                    "alreadyExported": {
                        "type": "boolean",
                        "description": "Has your credit pool received this record before, on any surface?"
                    },
                    "updatedSinceExport": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Has its content changed since then? Null when you have never received it."
                    },
                    "lastExportedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "billed": {
                        "type": "boolean",
                        "description": "Did this record consume a credit on this call?"
                    },
                    "billingReason": {
                        "type": "string",
                        "enum": [
                            "first_delivery",
                            "content_changed",
                            "already_delivered_unchanged",
                            "already_delivered_housekeeping_only"
                        ],
                        "description": "`already_delivered_housekeeping_only` means our row was written but the payload we hand you is byte-identical to last time. You are charged on what you receive, not on our write volume."
                    },
                    "contentRevision": {
                        "type": "string",
                        "nullable": true,
                        "description": "16-hex fingerprint of this record's content. Published on every record so you can dedupe locally without trusting our classification at all."
                    },
                    "previousContentRevision": {
                        "type": "string",
                        "nullable": true
                    },
                    "changedGroups": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": [
                                "identity",
                                "location",
                                "landUse",
                                "status",
                                "scale",
                                "parties",
                                "documents",
                                "meetings"
                            ]
                        },
                        "description": "Which sections of the record moved. Always complete."
                    },
                    "changes": {
                        "type": "array",
                        "description": "Before/after for the monitored fields. Exact for those fields and silent about the rest — `changedGroups` is the complete answer.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "field": {
                                    "type": "string"
                                },
                                "label": {
                                    "type": "string"
                                },
                                "from": {
                                    "nullable": true
                                },
                                "to": {
                                    "nullable": true
                                }
                            }
                        }
                    },
                    "newEvidence": {
                        "type": "array",
                        "description": "Public filings attached to this project since we last delivered it. Pass `meetingDocumentId` to `GET /documents/{id}`.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "meetingDocumentId": {
                                    "type": "integer"
                                },
                                "title": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "meetingDate": {
                                    "type": "string",
                                    "format": "date",
                                    "nullable": true
                                },
                                "documentType": {
                                    "type": "string",
                                    "nullable": true
                                }
                            }
                        }
                    },
                    "changeSummary": {
                        "type": "string",
                        "nullable": true,
                        "description": "One deterministically templated sentence. No model generates it, so it is reproducible and cannot invent a status change on a record you paid for."
                    }
                }
            },
            "SyncMeta": {
                "type": "object",
                "properties": {
                    "schemaVersion": {
                        "type": "string",
                        "example": "2026-08-18"
                    },
                    "representation": {
                        "type": "string",
                        "enum": [
                            "compact",
                            "standard",
                            "full"
                        ]
                    },
                    "limit": {
                        "type": "integer"
                    },
                    "creditsUsed": {
                        "type": "integer"
                    },
                    "creditsRemaining": {
                        "type": "integer"
                    },
                    "trialTruncation": {
                        "$ref": "#/components/schemas/TrialTruncation"
                    },
                    "searchMethod": {
                        "type": "string"
                    },
                    "appliedFilters": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "appliedDefaults": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "resolvedFrom": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "warnings": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "duplicatesCollapsed": {
                        "type": "integer"
                    },
                    "collapseApplied": {
                        "type": "boolean"
                    },
                    "delivery": {
                        "$ref": "#/components/schemas/DeliveryMeta"
                    },
                    "sync": {
                        "$ref": "#/components/schemas/SyncCursorMeta"
                    }
                }
            },
            "SyncCursorMeta": {
                "type": "object",
                "description": "Where the walk got to. `cursor` is the only value you need to keep; the rest is published so progress can be reasoned about without decoding it.",
                "properties": {
                    "cursor": {
                        "type": "string",
                        "description": "Send this back as `?cursor=` for the next page. Opaque — its contents are ours and its format can change; treat it as a token."
                    },
                    "hasMore": {
                        "type": "boolean",
                        "description": "False only when the index was exhausted AND this page held everything left. That is the one state on which it is safe to stop."
                    },
                    "watermark": {
                        "type": "string",
                        "format": "date-time",
                        "description": "The last-updated instant the walk has reached, UTC. Derive nothing from your own clock — this is the only clock the cursor is measured against."
                    },
                    "highWater": {
                        "type": "string",
                        "format": "date-time",
                        "description": "The upper bound frozen when this sync started. Records changed after it belong to your next sync, which is what lets this one finish on a busy corpus."
                    },
                    "emitted": {
                        "type": "integer",
                        "description": "Records returned so far in this walk."
                    },
                    "pageSize": {
                        "type": "integer"
                    },
                    "candidatesScanned": {
                        "type": "integer",
                        "description": "Index hits examined to build this page."
                    }
                }
            },
            "ProjectCountResponse": {
                "type": "object",
                "description": "Free. Carries no record identity of any kind — no ids, no names, no samples, no facets.",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "matchCount": {
                                "type": "integer",
                                "description": "Distinct project records matching. A lower bound when `matchCountIsExact` is false."
                            },
                            "matchCountIsExact": {
                                "type": "boolean"
                            },
                            "matchCountBasis": {
                                "type": "string",
                                "enum": [
                                    "enumerated",
                                    "scan_ceiling_reached"
                                ],
                                "description": "`enumerated` implies exact; `scan_ceiling_reached` implies a lower bound. They can never disagree with `matchCountIsExact`."
                            },
                            "countedAs": {
                                "type": "string",
                                "enum": [
                                    "distinct_projects"
                                ],
                                "description": "One unit is one project record. Never a count of index rows."
                            },
                            "scanCeiling": {
                                "type": "integer",
                                "example": 10000
                            },
                            "billable": {
                                "type": "object",
                                "description": "What you would actually be charged. Lower than `matchCount` where the pool already holds unchanged copies.",
                                "properties": {
                                    "records": {
                                        "type": "integer"
                                    },
                                    "credits": {
                                        "type": "integer"
                                    },
                                    "creditRate": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "isUpperBound": {
                                        "type": "boolean",
                                        "description": "Always true, and one-directional: the charge can only come in lower than the quote, never higher."
                                    },
                                    "nonBillable": {
                                        "type": "object",
                                        "properties": {
                                            "alreadyDeliveredUnchanged": {
                                                "type": "integer"
                                            },
                                            "ledgerApplied": {
                                                "type": "boolean",
                                                "description": "False when delivery history could not be read, so everything was priced as new."
                                            }
                                        }
                                    }
                                }
                            },
                            "affordability": {
                                "type": "object",
                                "properties": {
                                    "affordable": {
                                        "type": "boolean"
                                    },
                                    "blockReason": {
                                        "type": "string",
                                        "nullable": true,
                                        "enum": [
                                            "insufficient_credits",
                                            "credits_exhausted",
                                            "subscription_required",
                                            null
                                        ]
                                    },
                                    "shortfallCredits": {
                                        "type": "integer"
                                    },
                                    "maxAffordableRecords": {
                                        "type": "integer",
                                        "nullable": true,
                                        "description": "Null for an actor who is never debited."
                                    },
                                    "boundBy": {
                                        "type": "string",
                                        "enum": [
                                            "period_balance"
                                        ]
                                    },
                                    "unlimited": {
                                        "type": "boolean"
                                    }
                                }
                            },
                            "ordering": {
                                "type": "object",
                                "description": "The published ordering policy for this request.",
                                "properties": {
                                    "sort": {
                                        "type": "string"
                                    },
                                    "order": {
                                        "type": "string",
                                        "enum": [
                                            "asc",
                                            "desc"
                                        ]
                                    },
                                    "tiebreak": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Secondary sort key. **Currently null**: records sharing a sort value have no defined order between them, so paging a tie-heavy sort is not guaranteed stable."
                                    },
                                    "meaning": {
                                        "type": "string"
                                    }
                                }
                            },
                            "truncation": {
                                "type": "object",
                                "description": "What happens to the metered request if the balance cannot cover it.",
                                "properties": {
                                    "policy": {
                                        "type": "string",
                                        "enum": [
                                            "refuse",
                                            "trial_truncate"
                                        ],
                                        "description": "Paid plans are refused whole and never partially delivered; trial keys truncate to what the trial balance affords and say so."
                                    },
                                    "wouldTruncate": {
                                        "type": "boolean"
                                    },
                                    "deliverableRecords": {
                                        "type": "integer",
                                        "nullable": true
                                    },
                                    "explanation": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    },
                    "meta": {
                        "type": "object",
                        "properties": {
                            "schemaVersion": {
                                "type": "string",
                                "example": "2026-08-18"
                            },
                            "representation": {
                                "type": "string",
                                "enum": [
                                    "compact",
                                    "standard",
                                    "full"
                                ]
                            },
                            "credits": {
                                "type": "object",
                                "properties": {
                                    "limit": {
                                        "type": "integer"
                                    },
                                    "used": {
                                        "type": "integer"
                                    },
                                    "remaining": {
                                        "type": "integer"
                                    },
                                    "charged": {
                                        "type": "integer",
                                        "enum": [
                                            0
                                        ],
                                        "description": "Always zero."
                                    },
                                    "periodStart": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "periodEnd": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "isTeamPool": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    },
                    "links": {
                        "type": "object",
                        "properties": {
                            "self": {
                                "type": "string"
                            },
                            "search": {
                                "type": "string",
                                "description": "The metered route carrying the identical filters."
                            },
                            "docs": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "ProjectDetailResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/ProjectRecord"
                    },
                    "meta": {
                        "type": "object",
                        "properties": {
                            "schemaVersion": {
                                "type": "string",
                                "example": "2026-08-18"
                            },
                            "representation": {
                                "type": "string",
                                "enum": [
                                    "compact",
                                    "standard",
                                    "full"
                                ]
                            },
                            "creditsUsed": {
                                "type": "integer",
                                "description": "Zero when this credit pool already held an up-to-date copy of this record — it is not re-billed (#44)."
                            },
                            "creditsRemaining": {
                                "type": "integer"
                            },
                            "delivery": {
                                "$ref": "#/components/schemas/DeliveryMeta"
                            }
                        }
                    }
                }
            },
            "DocumentResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/Document"
                    },
                    "meta": {
                        "type": "object",
                        "properties": {
                            "creditsUsed": {
                                "type": "integer"
                            },
                            "creditsRemaining": {
                                "type": "integer"
                            }
                        }
                    }
                }
            },
            "Document": {
                "type": "object",
                "description": "A source meeting document (council/commission meeting, agenda packet, staff report, etc.).",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "meetingDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "type": {
                        "type": "string",
                        "nullable": true
                    },
                    "category": {
                        "type": "string"
                    },
                    "city": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": "string"
                            },
                            "state": {
                                "type": "string"
                            }
                        }
                    },
                    "county": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": "string"
                            },
                            "state": {
                                "type": "string"
                            }
                        }
                    },
                    "specialDistrict": {
                        "type": "object",
                        "nullable": true
                    },
                    "filePath": {
                        "type": "string",
                        "nullable": true,
                        "description": "S3-relative path to the source PDF."
                    },
                    "fileSize": {
                        "type": "integer",
                        "nullable": true
                    },
                    "sourceUrl": {
                        "type": "string",
                        "nullable": true
                    },
                    "sourceUrlId": {
                        "type": "integer",
                        "nullable": true
                    },
                    "rawText": {
                        "type": "string",
                        "nullable": true,
                        "description": "Full extracted text. Can be very large."
                    },
                    "summary": {
                        "type": "string",
                        "nullable": true,
                        "description": "LLM-generated summary."
                    },
                    "analysisV2": {
                        "type": "object",
                        "nullable": true,
                        "description": "Structured analysis extracted from the document."
                    },
                    "officialsPresent": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "topics": {
                        "type": "string",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "htmlContext": {
                        "type": "string",
                        "nullable": true
                    },
                    "extractionMethod": {
                        "type": "string",
                        "nullable": true
                    },
                    "contextConfidenceScore": {
                        "type": "integer",
                        "nullable": true
                    },
                    "processed": {
                        "type": "boolean"
                    },
                    "processedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "propertiesExtracted": {
                        "type": "boolean"
                    },
                    "propertiesExtractedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "audited": {
                        "type": "boolean"
                    },
                    "auditedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "imagesExtracted": {
                        "type": "boolean"
                    },
                    "imagesExtractedAt": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "extractionFailed": {
                        "type": "boolean"
                    },
                    "createdAt": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updatedAt": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "TaxonomyTreeResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "projectTypes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "name": {
                                            "type": "string"
                                        },
                                        "subtypes": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "assetClasses": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "LabelListResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "StateListResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/State"
                        }
                    },
                    "meta": {
                        "$ref": "#/components/schemas/GeographyScopeMeta"
                    }
                }
            },
            "GeographyScopeMeta": {
                "type": "object",
                "description": "The geographic ceiling on your plan, stated once instead of inferred from the per-state `entitled` flags.",
                "properties": {
                    "geographyScope": {
                        "type": "string",
                        "enum": [
                            "nationwide",
                            "states",
                            "counties",
                            "none"
                        ],
                        "description": "The shape of your entitlement. `nationwide` reaches every state without listing any; `none` is a plan that includes no API geography."
                    },
                    "entitledStateIds": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "integer"
                        },
                        "description": "**Null means every state**, not none — it is the nationwide case. An empty array means nowhere. Treating the two alike turns a denial into unrestricted access, so branch on `geographyScope` if that distinction is easier to hold."
                    },
                    "countyRestricted": {
                        "type": "boolean",
                        "description": "True on a county-grain plan, where `entitled` on a state means \"part of this state\". Use `/locations/states/{id}/counties` to see which."
                    }
                }
            },
            "StateResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/State"
                    },
                    "meta": {
                        "$ref": "#/components/schemas/GeographyScopeMeta"
                    }
                }
            },
            "State": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "abbreviation": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 2
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true
                    },
                    "entitled": {
                        "type": "boolean",
                        "description": "Whether **your key** may filter on this state. False means a query naming it returns `403 geographic_access_denied`. Always true on a nationwide plan. Every state is listed either way, so this is the field to build a picker against — not the presence of the row."
                    }
                }
            },
            "CountyListResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/County"
                        }
                    }
                }
            },
            "CountyDetailResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/CountyDetail"
                    }
                }
            },
            "County": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "fipsCode": {
                        "type": "string",
                        "nullable": true
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true
                    }
                }
            },
            "CountyDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/County"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "stateId": {
                                "type": "integer"
                            },
                            "stateName": {
                                "type": "string"
                            }
                        }
                    }
                ]
            },
            "CityListResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/City"
                        }
                    }
                }
            },
            "CityDetailResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/CityDetail"
                    }
                }
            },
            "City": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "latitude": {
                        "type": "number",
                        "nullable": true
                    },
                    "longitude": {
                        "type": "number",
                        "nullable": true
                    }
                }
            },
            "CityDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/City"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "stateId": {
                                "type": "integer"
                            },
                            "stateName": {
                                "type": "string"
                            }
                        }
                    }
                ]
            },
            "CreditBalanceResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "plan": {
                                "type": "string",
                                "description": "Internal plan name (e.g. `single_state`)."
                            },
                            "planDisplayName": {
                                "type": "string",
                                "description": "Human-friendly plan label (e.g. `1 State`)."
                            },
                            "creditsLimit": {
                                "type": "integer"
                            },
                            "creditsUsed": {
                                "type": "integer"
                            },
                            "creditsRemaining": {
                                "type": "integer"
                            },
                            "periodStart": {
                                "type": "string",
                                "format": "date"
                            },
                            "periodEnd": {
                                "type": "string",
                                "format": "date"
                            },
                            "resetsAt": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "Next reset instant. Null for a one-off trial allowance."
                            },
                            "rateLimit": {
                                "type": "integer"
                            },
                            "rateLimitPer": {
                                "type": "string",
                                "example": "minute"
                            },
                            "isTeamPool": {
                                "type": "boolean",
                                "description": "Whether this balance is shared by a team."
                            },
                            "poolUserId": {
                                "type": "integer",
                                "description": "Owner of the credit pool used by this key."
                            }
                        }
                    },
                    "meta": {
                        "type": "object",
                        "required": [
                            "requestId"
                        ],
                        "properties": {
                            "requestId": {
                                "type": "string",
                                "description": "Matches X-Request-Id."
                            }
                        }
                    }
                }
            }
        },
        "responses": {
            "Unauthorized": {
                "description": "Missing or invalid API key.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "missing_api_key",
                                "message": "API key is required. Include it as Authorization: Bearer bwk_live_... or X-API-Key: bwk_live_...",
                                "param": null,
                                "details": {},
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#missing_api_key",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "PaymentRequired": {
                "description": "Subscription missing, credits exhausted, or the request costs more than the balance holds.\n\n* `subscription_required` — no active paid plan or trial behind this key.\n* `credits_exhausted` — the balance cannot cover even one record. Paid balances refill on the 1st; trial credits never do.\n* `insufficient_credits` — the balance has credits left, but fewer than this request would spend. **No records are returned and nothing is charged**; `details.quote` states the cost, what remains, and how many records the remainder would buy, so the request can be narrowed and retried. Free-trial keys are truncated instead of refused here — see `meta.trialTruncation`.\n* `enrichment_requires_paid_plan` — `include=contacts` (Find Contact Info) is a paid-plan toggle. Record credits may still remain. Drop the parameter or upgrade.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "credits_exhausted",
                                "message": "You have used all your API credits for this billing period. Credits reset on the 1st of each month.",
                                "param": null,
                                "details": {
                                    "creditsUsed": 5000,
                                    "creditsLimit": 5000,
                                    "resetsAt": "2026-06-01T00:00:00Z"
                                },
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#credits_exhausted",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "EnrichmentUnavailable": {
                "description": "Find Contact Info is compiled in but not switched on for this environment (`501 enrichment_unavailable`). Drop `include=contacts` and retry. Nothing was charged.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "enrichment_unavailable",
                                "message": "Finding contact info is not switched on yet.",
                                "param": "include",
                                "details": {},
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#enrichment_unavailable",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "UnknownRepresentation": {
                "description": "An unrecognised `representation` (or, on search, an unrecognised `format`). The only representations are `compact`, `standard`, `full`. Nothing is returned and **nothing is charged** — a payload shape you did not ask for is not something to bill for, and silently serving the default would hand you a record set your client cannot parse.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "invalid_request",
                                "message": "Unknown representation \"verbose\". Valid values: compact, standard, full.",
                                "param": "representation",
                                "details": {
                                    "supported": [
                                        "compact",
                                        "standard",
                                        "full"
                                    ]
                                },
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#invalid_request",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "GeographicAccessDenied": {
                "description": "Requested state filter falls outside the licensed geography of the calling subscription.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "geographic_access_denied",
                                "message": "Your subscription does not include access to one or more requested states.",
                                "param": null,
                                "details": {},
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#geographic_access_denied",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "RateLimitExceeded": {
                "description": "Too many requests in the trailing 60 seconds. Limits are per API key: 60 requests per minute on any paid plan, 10 per minute on a free-trial key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 also carries Retry-After. Before authentication, a missing credential uses a 10-per-minute source-IP bucket and an unknown or unusable Boardwalk-shaped key uses its own 10-per-minute credential-digest bucket.",
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    },
                    "Retry-After": {
                        "description": "Seconds to wait before retrying.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    "X-RateLimit-Limit": {
                        "description": "Requests allowed per minute for the applicable key or pre-authentication bucket.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    "X-RateLimit-Remaining": {
                        "description": "Requests left in the current window.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    "X-RateLimit-Reset": {
                        "description": "Unix timestamp at which the window resets.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "rate_limit_exceeded",
                                "message": "Rate limit of 60 requests per minute exceeded. Retry in 12 seconds.",
                                "param": null,
                                "details": {
                                    "retryAfterSeconds": 12
                                },
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#rate_limit_exceeded",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                }
            },
            "SearchUnavailable": {
                "description": "The project search backend is temporarily unavailable, so no results or count could be produced. Nothing is charged. This condition is never reported as an empty page or a count of zero.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "search_unavailable",
                                "message": "Project search is temporarily unavailable. Retry shortly; nothing was charged.",
                                "param": null,
                                "details": {},
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#search_unavailable",
                                "requestId": "req_01K1EXAMPLE000000000000000"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            }
        }
    }
}
