{
    "openapi": "3.0.3",
    "info": {
        "title": "Boardwalk Land Use Intelligence API",
        "version": "2026-08-27",
        "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**\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. A key\nsurvives its creator's departure **once a team owner reassigns it** — the secret,\nthe id and your deployed configuration all stay put and only the attributed actor\nchanges; a key still attributed to a closed account stops authenticating. A team\nowner can see and stop every key that can spend the team's credits.\n\nYou may hold **2 active live keys per user** at any time, on every plan; a third\nmint is refused. Rotation does not count against that ceiling. Rotating a key\nissues the replacement immediately and keeps the previous key working for a grace\nwindow you choose — **1, 24 (the default) or 168 hours** — so you can deploy at\nyour own pace. While a key is in that window its responses carry\n`X-Boardwalk-Key-Rotating: true` and a `Warning` header naming the moment it\nstops. Minting a second key is not rotating: it starts no grace window, and the\nold key keeps working until you revoke it.\n\nA key is backed either by an active paid subscription (County, State, Multi-State,\nNational, or API Only 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, project types, 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| `POST /enrichments` | **1 credit per project unlocked.** County, State, and National: 1 credit per project the first time this account receives email or phone for it. Standalone API Only: included on records this pool has already purchased — unpurchased ids are skipped as `notPurchased`. A live free trial spends the separate 5-lookup grant (not the 50 record-export credits). Empty lookups cost nothing. Credits are charged when the job delivers contacts, not when it is queued. |\n\nThe billable unit depends on the plan. **County, State, and National:** searching, viewing,\nand exporting records is free; **1 credit per project** the first time this account receives\nemail or phone. **Standalone API Only:** **1 credit per delivered record**; Find Contact Info\non a purchased record is included. Empty lookups cost nothing. Paid credits reset on the 1st\nof each month and do not roll over. Check your remaining balance with `GET /account/credits`\nor read the `X-Credits-Remaining` response header on any billed call.\n\n## Running out of credits\n\n**A page is delivered whole or refused whole — never trimmed.** A request\ndelivers at most one page; the match set is paged, and the free\n`GET /projects/count` prices the whole set before you spend anything. `402\ninsufficient_credits` fires when the page a request would deliver costs more\nthan the balance has left, and then **nothing is returned and nothing is\ncharged**. The error body carries a quote — `details.quote.creditsRequired` is\nthe refused page's cost, `creditsRemaining` what is left,\n`affordableRecordCount` the `limit` to retry with, and `countUrl` re-prices the\nset for free. Because a paid page is never trimmed, a short page always means\n\"that is all that matched\", never \"that is all you could afford\". When the\nbalance cannot pay for even one record the refusal is `402 credits_exhausted`\ninstead, with no quote. Re-reads of unchanged records you already purchased bill\n0 credits, and a page or record that bills 0 is served free even at exactly 0\nbalance — the exhausted refusal only fires when the response would bill.\n\n## Free trial\n\nA free trial includes **50 record-export credits** (search, CSV, MCP — mix and\nmatch) and **5 Find Contact Info credits in total**. Neither grant\nrefills. Create a free account, mint a key under Settings → API, and spend those credits\nwith a `bwk_live_` key. Access is also limited to the geography the trial grants on the map.\n\nA trial key that cannot afford a full page is truncated to what remains and flagged with\n`meta.trialTruncation` rather than refused with 402. Once the 50 record credits are gone,\nfurther billed record pulls return `402 credits_exhausted`. The 5 Find Contact Info lookups\nare a separate lifetime grant.\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` | 21 | agents and list views; small enough to hold a hundred records in a prompt |\n| `standard` (default) | 67 | the calibrated field set, matching the CSV export |\n| `full` | 85 | adds decisions with named votes, document metadata and `rawText` |\n\nEach representation nests inside the next. **On County, State, and National, viewing any representation is free.** Standalone API Only and the free trial charge 1 credit per delivered record. Find Contact Info is 1 credit per project on County/State/National the first time this account receives email or phone, and is included on API Only records already purchased. 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": "Project types",
            "description": "Building Type tree (type, subtype, class) and application types."
        },
        {
            "name": "Locations",
            "description": "States, counties, and cities. IDs from here are used as filter values in project search."
        },
        {
            "name": "Reference",
            "description": "Value catalogues. `statuses` and `decision-bodies` are filter vocabularies used by search; `owner-types` is a labelling vocabulary only — its filter was withdrawn."
        },
        {
            "name": "Exports",
            "description": "CSV export jobs queued from the product, from POST /exports, or from search format=csv."
        },
        {
            "name": "Enrichment",
            "description": "Find contact info. County, State, and National: 1 credit per project the first time this account receives email or phone. Standalone API Only: included on records already purchased. Empty lookups cost nothing."
        },
        {
            "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."
        },
        {
            "name": "Alerts",
            "description": "Standing searches that run on a cadence and deliver into your account. Configuration and runs are free. Find Contact Info on delivered records is billed separately when email or phone is found."
        },
        {
            "name": "Lists",
            "description": "Saved lists of projects, shared with you or with your team. Reading a list's configuration is free. Pulling its records uses the same record meter as search: free on County, State, and National; 1 credit per new or changed record on Standalone API Only and the free trial. Find Contact Info is billed separately when email or phone is delivered."
        }
    ],
    "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.** County, State, and National: searching and viewing records does not spend credits. Standalone API Only and the free trial: 1 credit per delivered record that is new to this pool or changed since last delivery. Find Contact Info is 1 credit per project on County/State/National the first time this account receives email or phone, and is included on API Only after the record is purchased.\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": "Building Type (top level), 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": "Building Type (2nd level). 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": "Building Type class (3rd level), 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": "Building Types (2nd level) to exclude. Applied after the Building Type match, 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": "Building Type classes 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 Building Type has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any Building Type level, so a project matches when it has the type you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (propertyTypes, subtypes, assetClasses). Every delivered record names which of its types matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the type 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": "Entitlement Status. 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": "Application Type — 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": "Construction Type — 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": "projectSizes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is: large, medium or small — the same Project Size vocabulary the product uses. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `projectSize`, `constructionMagnitudes`, `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadsOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads. Accepted aliases: `constructionLeadOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionDetails",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction details were extracted for this record. Accepted aliases: `hasConstructionIntel`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "includeGovernmentDecisions",
                        "in": "query",
                        "required": false,
                        "description": "Show Non-Real Estate Govt. Decisions. Defaults to false, matching the map — which reduces what a naive query bills for. Accepted aliases: `includeCivic`, `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "governmentDecisionSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicSubtypes`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "governmentDecisionAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicAssetClasses`.",
                        "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": "inFemaFloodZone",
                        "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: `inSfha`.",
                        "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 residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for commercial square footage. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for commercial square footage. 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": "projectName",
                        "in": "query",
                        "required": false,
                        "description": "Project name search. Matches the project's name and display name only, as an exact phrase. Accepted aliases: `name`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "developerName",
                        "in": "query",
                        "required": false,
                        "description": "Developer or company name search over the parties named on the filing (developer, applicant, builder, owner, contractor, architect), as an exact phrase. Accepted aliases: `developer`, `company`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requiresZoningChange",
                        "in": "query",
                        "required": false,
                        "description": "Requires Zoning Change — keeps only records whose request changes the site's zoning (the record's isRezone field). Omit it, rather than sending false, to include everything. Accepted aliases: `isRezone`, `rezoneOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "projectIds",
                        "in": "query",
                        "required": false,
                        "description": "Exact record ids to fetch back — the read-back filter for records you already purchased (re-reads of unchanged owned records cost 0 credits). Positive integers, at most 100 per request. No default date window applies to an id selection (send dateRange or meetingDate bounds to window one deliberately). On GET /projects/search and /projects/sync it combines (AND) with every other filter; on the free GET /projects/count it must be the only filter — the count prices an id set as-is. An unknown id, or one outside your other filters or licensed geography, simply does not match. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ids`.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "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": "JSON only: results per page (1–100). Ignored on `format=csv` (the file is the full filter match).",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "description": "JSON only: pagination offset (0-based). Prefer this when paging. Mutually exclusive with `page` when both are sent: offset wins. Ignored on `format=csv`.",
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "description": "JSON only: 1-based page number. When `offset` is omitted, treated as `offset = (page - 1) * limit`. Ignored on `format=csv`.",
                        "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 of the **full filter match** (same survivor set as `GET /projects/count`, scan ceiling 10,000), not one JSON page. Already-owned unchanged rows stay in the file and reserve 0 credits. HTTP 202 with absolute `pollUrl` / `downloadUrl` / `webExportsUrl`. Add `include=contacts` on a paid plan or live trial to turn on Find Contact Info. Optional `maxCredits` refuses the queue if the billable charge would exceed it. `csv` fails closed when your delivery history cannot be read: `503 delivery_ledger_unavailable`, nothing queued, no credits reserved — retry, or use `format=json`.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "json",
                                "csv"
                            ],
                            "default": "json"
                        }
                    },
                    {
                        "name": "maxCredits",
                        "in": "query",
                        "description": "`format=csv` only: refuse the export (400) if new-or-changed rows would reserve more than this many credits. Already-owned unchanged rows do not count. Omit to queue whatever the pool can afford.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        }
                    },
                    {
                        "name": "include",
                        "in": "query",
                        "description": "Set to `contacts` to turn on Find Contact Info for the projects in this request (paid plans and live trials). 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. On `format=csv`, `contactOptions.cachedOnly` is refused — the CSV job always runs the live lookup — while the other options (`minConfidence`, `maxProjects`, `companyOnly`) are accepted and honoured.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "{\"cachedOnly\":true}"
                    },
                    {
                        "name": "deliveryMode",
                        "in": "query",
                        "description": "`all` (default) returns every matching record and discloses each one's delivery state. `new` returns only records your pool has never received: a record you already own is withheld **whether or not it has changed since** — use `GET /projects/sync` for updates. Withheld records are counted in `meta.delivery.excludedPreviouslyDelivered` and are never billed. (Under `all`, an owned record that has changed since your last delivery is served and bills 1 credit; only an owned, unchanged record is free.)",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "new"
                            ],
                            "default": "all"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "JSON page of projects with pagination + credit usage metadata. Also returned with `format=csv` when nothing matched (`status: no_matching_rows`; 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`: full-match export job accepted. Poll `pollUrl` / download via `downloadUrl`. Same file appears on the product `/exports` page. Already-owned rows stay in the file at 0 credits. `include=contacts` (paid or live trial) 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"
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "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 it is billable cost, never raw match count, that each search page is weighed against. A second identical request costs less than the first.\n\n**Affordability is set-scoped.** `affordability.affordable: false` means the whole remaining set does not fit your balance — not that your next search call fails. Search delivers a page at a time and refuses only a page it cannot bill whole, so you can still page from the top, collect `maxAffordableRecords` records, and stop without overspending; the first page that does not fit is refused.\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": "Building Type (top level), 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": "Building Type (2nd level). 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": "Building Type class (3rd level), 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": "Building Types (2nd level) to exclude. Applied after the Building Type match, 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": "Building Type classes 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 Building Type has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any Building Type level, so a project matches when it has the type you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (propertyTypes, subtypes, assetClasses). Every delivered record names which of its types matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the type 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": "Entitlement Status. 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": "Application Type — 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": "Construction Type — 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": "projectSizes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is: large, medium or small — the same Project Size vocabulary the product uses. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `projectSize`, `constructionMagnitudes`, `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadsOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads. Accepted aliases: `constructionLeadOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionDetails",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction details were extracted for this record. Accepted aliases: `hasConstructionIntel`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "includeGovernmentDecisions",
                        "in": "query",
                        "required": false,
                        "description": "Show Non-Real Estate Govt. Decisions. Defaults to false, matching the map — which reduces what a naive query bills for. Accepted aliases: `includeCivic`, `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "governmentDecisionSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicSubtypes`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "governmentDecisionAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicAssetClasses`.",
                        "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": "inFemaFloodZone",
                        "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: `inSfha`.",
                        "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 residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for commercial square footage. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for commercial square footage. 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": "projectName",
                        "in": "query",
                        "required": false,
                        "description": "Project name search. Matches the project's name and display name only, as an exact phrase. Accepted aliases: `name`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "developerName",
                        "in": "query",
                        "required": false,
                        "description": "Developer or company name search over the parties named on the filing (developer, applicant, builder, owner, contractor, architect), as an exact phrase. Accepted aliases: `developer`, `company`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requiresZoningChange",
                        "in": "query",
                        "required": false,
                        "description": "Requires Zoning Change — keeps only records whose request changes the site's zoning (the record's isRezone field). Omit it, rather than sending false, to include everything. Accepted aliases: `isRezone`, `rezoneOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "projectIds",
                        "in": "query",
                        "required": false,
                        "description": "Exact record ids to fetch back — the read-back filter for records you already purchased (re-reads of unchanged owned records cost 0 credits). Positive integers, at most 100 per request. No default date window applies to an id selection (send dateRange or meetingDate bounds to window one deliberately). On GET /projects/search and /projects/sync it combines (AND) with every other filter; on the free GET /projects/count it must be the only filter — the count prices an id set as-is. An unknown id, or one outside your other filters or licensed geography, simply does not match. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ids`.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "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 of the whole set, and whether that set fits the caller's balance. 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.** County, State, and National: searching and syncing records does not spend credits. Standalone API Only and the free trial: 1 credit per delivered record that is new to this pool or changed since last delivery; unchanged owned records bill 0. Find Contact Info is billed separately on County/State/National, and included on API Only after the record is purchased. Records you already hold and that have not changed come back with `delivery.alreadyExported: true` and `delivery.updatedSinceExport: false`.\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": "Building Type (top level), 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": "Building Type (2nd level). 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": "Building Type class (3rd level), 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": "Building Types (2nd level) to exclude. Applied after the Building Type match, 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": "Building Type classes 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 Building Type has to be the project's primary one to count as a match. Defaults to primary_or_secondary whenever you filter on any Building Type level, so a project matches when it has the type you asked for — whether that is its headline use or one component of a larger development. The same rule applies at all three levels (propertyTypes, subtypes, assetClasses). Every delivered record names which of its types matched, and at which level, in `landUses[].matchedOn`. Send primary_only to count a project only when the type 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": "Entitlement Status. 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": "Application Type — 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": "Construction Type — 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": "projectSizes",
                        "in": "query",
                        "required": false,
                        "description": "How large the construction is: large, medium or small — the same Project Size vocabulary the product uses. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `projectSize`, `constructionMagnitudes`, `constructionMagnitude`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "constructionLeadsOnly",
                        "in": "query",
                        "required": false,
                        "description": "true keeps only records the pipeline marked as real construction leads. Accepted aliases: `constructionLeadOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "hasConstructionDetails",
                        "in": "query",
                        "required": false,
                        "description": "Whether construction details were extracted for this record. Accepted aliases: `hasConstructionIntel`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "includeGovernmentDecisions",
                        "in": "query",
                        "required": false,
                        "description": "Show Non-Real Estate Govt. Decisions. Defaults to false, matching the map — which reduces what a naive query bills for. Accepted aliases: `includeCivic`, `showAllRecords`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "governmentDecisionSubtypes",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicSubtypes`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "governmentDecisionAssetClasses",
                        "in": "query",
                        "required": false,
                        "description": "Narrows Govt. Decisions only. Requires includeGovernmentDecisions=true. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `civicAssetClasses`.",
                        "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": "inFemaFloodZone",
                        "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: `inSfha`.",
                        "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 residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "totalUnitCountMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for residential units. Inclusive. 0 is a real bound, not \"unset\". Accepted aliases: `unitCountMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "acreageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for acres. “Projects over 2 acres” → acreageMin=2. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMin`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "lotSizeSqftMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound in square feet for the same site area as acreage. Prefer acreageMin / acreageMax when you mean acres. Accepted aliases: `lotSizeMax`.",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMin",
                        "in": "query",
                        "required": false,
                        "description": "Lower bound for commercial square footage. Inclusive. 0 is a real bound, not \"unset\".",
                        "schema": {
                            "type": "number"
                        }
                    },
                    {
                        "name": "squareFootageMax",
                        "in": "query",
                        "required": false,
                        "description": "Upper bound for commercial square footage. 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": "projectName",
                        "in": "query",
                        "required": false,
                        "description": "Project name search. Matches the project's name and display name only, as an exact phrase. Accepted aliases: `name`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "developerName",
                        "in": "query",
                        "required": false,
                        "description": "Developer or company name search over the parties named on the filing (developer, applicant, builder, owner, contractor, architect), as an exact phrase. Accepted aliases: `developer`, `company`.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "requiresZoningChange",
                        "in": "query",
                        "required": false,
                        "description": "Requires Zoning Change — keeps only records whose request changes the site's zoning (the record's isRezone field). Omit it, rather than sending false, to include everything. Accepted aliases: `isRezone`, `rezoneOnly`.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "projectIds",
                        "in": "query",
                        "required": false,
                        "description": "Exact record ids to fetch back — the read-back filter for records you already purchased (re-reads of unchanged owned records cost 0 credits). Positive integers, at most 100 per request. No default date window applies to an id selection (send dateRange or meetingDate bounds to window one deliberately). On GET /projects/search and /projects/sync it combines (AND) with every other filter; on the free GET /projects/count it must be the only filter — the count prices an id set as-is. An unknown id, or one outside your other filters or licensed geography, simply does not match. Send one value, a comma-separated list, a JSON array, or repeat the parameter. Accepted aliases: `ids`.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$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"
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "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.** County, State, and National: free. Standalone API Only and the free trial: 1 credit the first time this pool receives the record. Email, phone, and LinkedIn stay withheld until this account has unlocked the project with Find Contact Info. A `404` also costs nothing.\n\nA project is served only where our current-generation extraction has covered it; ids outside that set return `404`. Recently ingested projects are the most likely to be in that state.",
                "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"
                            }
                        }
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/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:** County, State, and National: searching is free. Standalone API Only and the free trial: 1 credit per requested record, reserved at submit and settled against confirmed matches. Find Contact Info on results is 1 credit per project on County/State/National the first time this account receives email or phone, and is included on API Only after the record is purchased.\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\nState filters (`states`, `stateIds`, `state`, `stateId`) accept integer IDs, USPS abbreviations, or names — the same vocabulary as `GET /projects/search`. County and city filters remain integer IDs from `/locations/*`. 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.\n\n**Completion email:** when the job settles (completed, partial, failed, or cancelled), a pointer-only email — counts, credits, and the poll URL, never record data — is sent to the submitter's account address. It is on by default; send `notify: {\"email\": false}` to opt out. Failure and cancellation emails state the refund.\n\n**Cancellation:** `DELETE /projects/ai-search/jobs/{requestId}` cancels a queued job outright (full refund) or asks a running one to stop at the next batch boundary.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AiSearchRequest"
                            },
                            "example": {
                                "query": "multifamily apartment buildings over 100 units approved in Utah in 2025",
                                "states": [
                                    "UT"
                                ],
                                "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"
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "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.\n\nJobs are visible to the submitter and to anyone on the same credit pool — a teammate can poll a colleague's job before its 72-hour result window closes. Anyone else receives `404`.",
                "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "Job not found for this API user or their credit pool.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "410": {
                        "description": "Completed result expired (retained 72 hours). Submit a new search — the result cannot be recovered.\n\n**The body is the standard error envelope, not the job-status schema.** The response contract normalises every 4xx/5xx body, and 410 has no dedicated code today, so what ships is `error.code: \"invalid_request\"` with `error.message: \"Gone\"`; the job's own fields (`status: \"expired\"`, `requestId`, `creditsReserved`, `creditsCharged`, timestamps) arrive under `error.details`. **Branch on the `410` status, not on `error.code`** — the code here does not mean your request was malformed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiError"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Projects"
                ],
                "summary": "Cancel an asynchronous AI search job",
                "description": "Requests cancellation of a job.\n\nA **queued** job is cancelled immediately: no work has happened, the full reservation is refunded, and the `202` response echoes the terminal `cancelled` status. A **running** job has its cancel flag set (`202`); the worker observes it at the next batch boundary and settles the job as `partial` with `partialReason: cancelled_by_user` — confirmed billable records are charged, the unused remainder of the reservation is refunded, and everything confirmed so far is delivered on the poll.\n\nCancelling a job that already reached a terminal state is an idempotent no-op: `200` echoing the current status, nothing changed, nothing charged.\n\nJobs are visible to the submitter and to anyone on the same credit pool; anyone else receives `404`.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Job `requestId` from the create response.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "202": {
                        "description": "Cancellation accepted. A queued job echoes `status: cancelled` with the full reservation in `creditsRefunded`; a running job echoes `status: running` with `cancelRequested: true` and settles at the next batch boundary.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchJobCancel"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "200": {
                        "description": "The job was already terminal; idempotent no-op echoing the current state.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AiSearchJobCancel"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "Job not found for this API user or their credit pool.",
                        "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 come from `delivery.newEvidence[].meetingDocumentId` on `GET /projects/sync` — that is the only place the customer surface publishes a meeting-document id. Project records on `/projects/search` and `/projects/{id}` carry `sourceDocumentUrl` (a direct link to the filing) rather than a document id, so a caller on those routes alone has no id to send here.\n\nOnly documents that have been through Boardwalk's current extraction standard are served here; a document that has not been analysed returns `404`. Documents ingested in the last few weeks are the most likely to be in that state.\n\n**Cost.** County, State, and National: free. Standalone API Only and the free trial: 1 credit per source document the first time this pool receives it.",
                "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"
                            }
                        }
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/taxonomy": {
            "get": {
                "tags": [
                    "Project types"
                ],
                "summary": "Full Building Type tree",
                "description": "Three-level hierarchy: Building Type → subtype → class. These are the same v2 labels `/projects/search` accepts for `type`, `subtype`, and `assetClass`. Free.",
                "responses": {
                    "200": {
                        "description": "Building Type 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": [
                    "Project types"
                ],
                "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": [
                    "Project types"
                ],
                "summary": "Project subtypes",
                "description": "Level-2 labels from the same v2 tree `/projects/search` matches against, 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": [
                    "Project types"
                ],
                "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": [
                    "Project types"
                ],
                "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": [
                    "Project types"
                ],
                "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 `counties` filter (aliases `county`, `countyId`, `countyIds`) 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"
                    }
                }
            }
        },
        "/account/preferences": {
            "get": {
                "tags": [
                    "Account"
                ],
                "summary": "Saved search preferences — free",
                "description": "Types, geography, optional website, and optional thumbs on example projects. Empty when first-run has not happened. A teammate with no row of their own inherits the team owner's blob (`inheritedFromTeam: true`). **Free.**",
                "responses": {
                    "200": {
                        "description": "Preferences blob. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Account"
                ],
                "summary": "Update search preferences — free",
                "description": "Merge the fields you send onto the caller's own row (never onto an inherited team row). **Free.**",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "lookingFor": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "geography": {
                                        "type": "object"
                                    },
                                    "website": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "notes": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "exampleProjectFeedback": {
                                        "type": "array"
                                    },
                                    "firstRunCompleted": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The saved blob.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Unknown field or invalid value.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/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\nEach row includes `alreadyOnThis` (every match except dismissed, including pending review) and `pendingReview` (matched, not yet saved). Pull those ids with `GET /alerts/{alertId}/matches` — do not re-run the filters.\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**Natural-language criteria.** `specificRequirement` (up to 500 characters) is a free-text requirement every delivered record must satisfy — the same evidence-verified matcher the product's alerts run. It can stand alone (an NL alert needs no `filters` at all) or narrow a structured filter set; each NL-matched record from `/alerts/{alertId}/matches` carries `whyThisMatched` and verbatim `matchEvidence`. An alert needs at least one of `filters` or `specificRequirement`.\n\n**Geography.** An alert with no `states`, `counties`, `cities` or geometry is a **nationwide** standing instruction, accepted only on a plan whose licensed geography is nationwide (API Only, National); on any other plan it is refused with `403` — a blank geography field is almost never a request for the whole country. The per-alert breadth caps below are likewise waived only on nationwide-entitled plans.\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, on every plan. The geography caps — 5 states, or 25 counties/cities, per alert — apply only to plans whose licensed geography is narrower than nationwide: an **API Only or National pool is exempt** and may hold a nationwide alert, or one spanning as many states as it likes. Breaching a cap on a narrower plan is a `403` naming `alert_geography_too_broad`; leaving geography blank there is a `403 alert_geography_required`. Up to 1,000 records materialised per run (default 100).",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "description": "At least one of `filters` or `specificRequirement` is required — an alert with no criteria at all is refused.",
                                "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. May be omitted when `specificRequirement` is set."
                                    },
                                    "specificRequirement": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 500,
                                        "description": "Natural-language requirement every delivered record must satisfy, matched through the evidence-verified pipeline — the same 500-character cap the web alert form stores. Omitted or null means structured-only; on PATCH, null removes it (an NL-only alert must keep at least one criterion)."
                                    },
                                    "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
                                    },
                                    "budget": {
                                        "type": "object",
                                        "description": "Optional alias. `budget.maxRecordsPerRun` is accepted the same as top-level `maxRecordsPerRun`. Alert responses always nest the ceiling under `budget`.",
                                        "properties": {
                                            "maxRecordsPerRun": {
                                                "type": "integer",
                                                "minimum": 1,
                                                "maximum": 1000
                                            }
                                        }
                                    },
                                    "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; or no geography / too broad a geography on a plan that is not nationwide-entitled) — 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`. `alreadyOnThis` is every match except dismissed (pending review stays in); `pendingReview` is how many of those are still waiting to be saved. `matchesUrl` pulls that set.",
                "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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 — free",
                "description": "Runs the alert immediately. **Free.** Searching and viewing matching records does not spend credits. Find Contact Info on those records is billed separately when email or phone is found.\n\n`Idempotency-Key` is **required**: it is what makes a retry replay the same delivery instead of creating a second run. Re-sending a key that already ran returns that run's delivery; a manual run that collides with a scheduled run for the same window does nothing.\n\n**Manual runs are capped at 3 per alert per calendar day of the service clock** (US Mountain Time, `America/Denver` — not UTC). The 4th attempt is refused with `429 manual_runs_exhausted` — nothing runs, and `Retry-After` plus `error.details.resetsAt` name that clock's next midnight, when the allowance refills. **Read `Retry-After` or `error.details.resetsAt` rather than computing the reset yourself**; the boundary moves with daylight saving. Replays and `already_running` collisions never spend an attempt, and scheduled cadence runs are not limited. For recurring delivery, set a cadence.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Nothing new ran. Two cases, distinguished by `data`:\n\n* **Replayed `Idempotency-Key`** — `data` is the delivery that key already produced, `meta.creditsUsed: 0`.\n* **Window collision with a scheduled run** — `data` is `{\"status\": \"already_running\"}` (a different shape entirely, with no delivery fields), `meta.creditsUsed: 0`. Read the delivery from `GET /alerts/{alertId}/deliveries`.\n\nNeither spends a manual-run attempt.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "201": {
                        "description": "The delivery: window, counts, credits charged, and the URL to fetch the records.\n\n**A run that cannot afford its billable selection is also a `201`, never a `402`.** It delivers nothing and charges nothing, and its `data` carries the refused delivery's `status` plus a `quote` telling you how far short the balance was.",
                        "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": {
                        "description": "A preflight refusal — `subscription_required` (no live plan). **Not** how an unaffordable run is reported: that is a `201` carrying a quote, described above.",
                        "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"
                            }
                        }
                    },
                    "429": {
                        "description": "`manual_runs_exhausted` — the alert already spent its 3 manual runs for this service-clock day (US Mountain Time; `Retry-After` and `error.details.resetsAt` name the reset — read them rather than computing it); or the standard per-minute rate limit.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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 projects already on this alert — free to read",
                "description": "Omit `deliveryId` to pull **every match except dismissed**, including projects still pending review. That is the same set the website table shows. **Free.** `meta.alreadyOnThis` is the full set; `meta.pendingReview` is how many of those are not yet saved. Managing pending review is a first-class use of this read.\n\nExtra search filters (`acreageMin`, `projectSizes`, …) apply only inside those existing ids.\n\nPass `deliveryId` only to re-read a specific past API run. Those records were charged when the run materialised them, so re-reading — repeatedly, from any member's key, until it expires — costs nothing. Each delivery record carries `delivery.alreadyExported`, `delivery.updatedSinceExport`, `delivery.lastExportedAt` and `delivery.billed`. Deliveries stay fetchable for 30 days; after that the records are still yours through search, free.",
                "parameters": [
                    {
                        "name": "alertId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "deliveryId",
                        "in": "query",
                        "required": false,
                        "description": "Omit to pull every match except dismissed (pending review stays in). Pass a past API-run id only when they asked for that 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
                        }
                    },
                    {
                        "name": "onlyNew",
                        "in": "query",
                        "description": "Only with `deliveryId`: keep rows that were not already exported at run time (`delivery.alreadyExported=false`).",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "name": "excludeSaved",
                        "in": "query",
                        "description": "Only with `deliveryId`: drop projects already on a saved list this caller can see.",
                        "schema": {
                            "type": "boolean"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Representation"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The match set (or one delivery's records). `meta.creditsUsed` is 0. Without `deliveryId`, `meta.pendingReview` is how many matches are still waiting to be saved.",
                        "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 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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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 (including the system **Saved** list, marked `isDefault: true`), plus the ones shared with you. Lists created from an alert delegate their sharing to that alert. System Saved stays unshareable. **Free.**\n\nEach entry carries its `lst_…` id, `source` (`manual`, `alert`, `filter`, `polygon`, `system`), `isDefault`, `share` block (`{mode, userIds, optOutUserIds}` — `userIds` is the live membership), and `alreadyOnThis` / `projectCount`. For an alert companion those counts are the parent alert's matches minus dismissed (pending review included) — the same set as `GET /alerts/{alertId}/matches`. `pendingReview` is how many of those matches are not yet saved. `null` for `filter`/`polygon` lists, which store a query, not records.",
                "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"
                    }
                }
            },
            "post": {
                "tags": [
                    "Lists"
                ],
                "summary": "Create a named list — free",
                "description": "Create a membership-backed list (`source=manual`) to save projects onto. **Free.** This is the \"new list\" option on the save chooser. Adding records is a separate `POST /lists/{listId}/projects`.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "description": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new list. `meta.creditsUsed` is 0.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing name.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/lists/{listId}/projects": {
            "post": {
                "tags": [
                    "Lists"
                ],
                "summary": "Add projects to a list — free",
                "description": "Add up to 100 project ids to a membership-backed list (Saved, alert companions, or a named `manual` list). **Free.** Idempotent per id. Filter and polygon lists refuse — they store criteria, not rows.",
                "parameters": [
                    {
                        "name": "listId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "projectIds"
                                ],
                                "properties": {
                                    "projectIds": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "maxItems": 100
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "At least one id was added.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "200": {
                        "description": "Every id was already on the list.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "No list your membership resolves, or an unknown project id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/lists/{listId}/projects/{projectId}": {
            "delete": {
                "tags": [
                    "Lists"
                ],
                "summary": "Remove a project from a list — free",
                "description": "Removes the project and its merge family from a membership-backed list. **Free.**",
                "parameters": [
                    {
                        "name": "listId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "projectId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`removed` is true when a row was deleted.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "No list your membership resolves has this id.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/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`**. For an alert companion, `alreadyOnThis` is every match except dismissed (pending review stays in) and `/results` is free. For a manual or Saved list, `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"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "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 — free",
                "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**Alert companions** return the parent alert's matches minus dismissed (pending review included) and are **free** — the same set as `GET /alerts/{alertId}/matches` without `deliveryId`.\n\n**Manual and Saved lists** are also free to read. Find Contact Info on those records is 1 credit per project the first time this account receives email or phone. Extra search filters (`acreageMin`, `propertyTypes`, `projectSizes`, …) apply only inside the ids already on this list. `meta.alreadyOnThis` is the unfiltered set; `meta.total` is the subset.\n\nFor a `filter`/`polygon` list this returns the stored `criteria` plus `links.search`, free — running the search happens on the 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"
                            }
                        }
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "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": "The `construction.owner_type` vocabulary — the values that appear on alert criteria and in CSV output. **Free.**\n\n**Not a `/projects/search` filter.** The `ownerTypes` filter was withdrawn on 2026-08-27; sending `ownerTypes=` to search, count or sync returns `400` with problem code `unknown_parameter`. This catalogue is published for reading and labelling the values, not for filtering on them.",
                "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"
                    }
                }
            }
        },
        "/enrichments": {
            "post": {
                "tags": [
                    "Enrichment"
                ],
                "summary": "Find contact info — 1 credit per newly unlocked project",
                "description": "Queue Find Contact Info for project ids. The pipeline runs asynchronously; poll `GET /enrichments/{id}` for progress.\n\n**Cost: 1 credit per project** the first time this account receives email or phone. Empty lookups cost nothing. A project this pool has already unlocked is skipped and is free to re-read. Credits are charged when the job delivers contacts, not when it is queued. A request that would exceed the remaining credit balance is refused with `402` and nothing queued.\n\nIDs whose contacts were already found for this pool, or attempted recently, are skipped as `skipped.alreadyEnriched`. When every ID is skipped the response is `200` with `status: nothing_to_enrich` and no job.\n\nEnrichment runs about a minute per lead at roughly two leads per project, so a large batch takes hours — a 100-project job is a multi-hour job. `estimatedCompletion` is a best-effort **estimate for polling cadence, not a deadline**. Up to 250 project IDs per job.\n\n**`Idempotency-Key` is required.** Re-sending the same key answers with the job the key already created and does not charge again.",
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Required. An opaque string (up to 255 characters of `A-Za-z0-9_.:-`) that makes a retry replay the same job instead of submitting a second one."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "projectIds"
                                ],
                                "properties": {
                                    "projectIds": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "description": "Projects to find contact info for."
                                    }
                                }
                            },
                            "example": {
                                "projectIds": [
                                    10754108,
                                    10754109
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "Job queued. `accepted` lists the IDs the job will attempt; `skipped` explains every ID it will not, and `pollUrl` is where progress lives.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "enrichmentJobId": {
                                            "type": "integer",
                                            "nullable": true
                                        },
                                        "status": {
                                            "type": "string",
                                            "enum": [
                                                "queued",
                                                "nothing_to_enrich"
                                            ]
                                        },
                                        "accepted": {
                                            "type": "array",
                                            "items": {
                                                "type": "integer"
                                            }
                                        },
                                        "skipped": {
                                            "type": "object",
                                            "properties": {
                                                "notPurchased": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "integer"
                                                    }
                                                },
                                                "alreadyEnriched": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "integer"
                                                    }
                                                }
                                            }
                                        },
                                        "estimatedCompletion": {
                                            "type": "string",
                                            "format": "date-time",
                                            "nullable": true,
                                            "description": "Best-effort completion estimate from the measured enrichment rate (~2 leads/project, ~1 minute/lead). An estimate, not a deadline — keep polling past it."
                                        },
                                        "pollUrl": {
                                            "type": "string",
                                            "nullable": true
                                        },
                                        "allowance": {
                                            "$ref": "#/components/schemas/EnrichmentAllowance"
                                        }
                                    }
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "200": {
                        "description": "Every ID was skipped — `status: nothing_to_enrich`, no job queued, no allowance consumed.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Missing `Idempotency-Key` header (param `Idempotency-Key`), missing/invalid projectIds, or more than the per-job cap. Nothing is queued.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "description": "Plan has no enrichment entitlement, or the monthly enrichment allowance would be exceeded (`enrichment_allowance_exceeded`, with used/limit/resets in details). Nothing is queued.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "409": {
                        "$ref": "#/components/responses/IdempotencyConflict"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    },
                    "501": {
                        "$ref": "#/components/responses/EnrichmentUnavailable"
                    },
                    "503": {
                        "description": "Enrichment temporarily unavailable, or the purchased-projects ledger could not be read (`enrichment_ledger_unavailable`). Fails closed: nothing is queued.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/enrichments/{id}": {
            "get": {
                "tags": [
                    "Enrichment"
                ],
                "summary": "Poll an enrichment job — free",
                "description": "Progress for a submitted enrichment job: `\"processed\": 57, \"requested\": 100, \"pending\": 43` while running, `status: completed` when done. `found` counts the projects where contacts were found so far. Free to poll. Jobs belong to the credit pool that queued them; anyone else's job is a 404.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Job state and progress counts.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "enrichmentJobId": {
                                            "type": "integer"
                                        },
                                        "status": {
                                            "type": "string",
                                            "description": "queued | running | completed | failed"
                                        },
                                        "requested": {
                                            "type": "integer"
                                        },
                                        "processed": {
                                            "type": "integer"
                                        },
                                        "found": {
                                            "type": "integer"
                                        },
                                        "pending": {
                                            "type": "integer"
                                        },
                                        "allowanceUsed": {
                                            "type": "integer",
                                            "nullable": true
                                        },
                                        "allowanceRemaining": {
                                            "type": "integer",
                                            "nullable": true
                                        },
                                        "notAttempted": {
                                            "type": "integer",
                                            "nullable": true,
                                            "description": "On a completed job the per-request ceilings stopped early: how many requested projects were never tried (= requested − processed). Those projects were not counted against the monthly allowance, and resubmitting exactly those ids is free to try. Absent when every requested project was attempted."
                                        },
                                        "note": {
                                            "type": "string",
                                            "nullable": true,
                                            "description": "Human-readable companion to `notAttempted`, present in the same case."
                                        },
                                        "error": {
                                            "type": "string",
                                            "nullable": true,
                                            "description": "Why the job failed, when `status` is `failed` (e.g. enrichment was disabled before the job ran — the allowance is refunded). Null otherwise."
                                        }
                                    }
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No such enrichment job on this account.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimitExceeded"
                    }
                }
            }
        },
        "/exports": {
            "get": {
                "tags": [
                    "Exports"
                ],
                "summary": "List export jobs — free",
                "description": "Team export history, including jobs queued via `POST /exports` or `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"
                    }
                }
            },
            "post": {
                "tags": [
                    "Exports"
                ],
                "summary": "Queue a CSV export",
                "description": "Queues the same product CSV as the map Export button. **Rows are free.** Find Contact Info on those rows is 1 credit per project the first time this account receives email or phone.\n\nPass **exactly one** of `alertId`, `listId`, or `projectIds` to export a saved set. Extra map filters (`acreageMin`, `propertyTypes`, …) apply only inside those ids. Omit all three and the body is a new search — same match as `GET /projects/search?format=csv`.\n\nA filter or polygon list has no saved records: pass `projectIds` you already pulled, or search filters without `listId`.\n\nReturns a receipt (HTTP 202). Poll `pollUrl` / download via `downloadUrl`. The file also appears on the product `/exports` page. Never streams CSV bytes on this route.",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "alertId": {
                                        "type": "string",
                                        "description": "Export every match on this alert except dismissed (pending review stays in)."
                                    },
                                    "listId": {
                                        "type": "string",
                                        "description": "Export a membership list, or the same curated set as its companion alert."
                                    },
                                    "projectIds": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "maxItems": 25000,
                                        "description": "The ids you already have after pull or further filtering. Alias: `ids`."
                                    },
                                    "ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "maxItems": 25000
                                    },
                                    "include": {
                                        "type": "string",
                                        "enum": [
                                            "contacts"
                                        ],
                                        "description": "Run Find Contact Info on the file (paid plans)."
                                    },
                                    "maxCredits": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "Refuse (400) if new-or-changed rows would reserve more than this many credits."
                                    }
                                },
                                "additionalProperties": true
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "Export job accepted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CsvExportJobAccepted"
                                }
                            }
                        },
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "200": {
                        "description": "`status: no_matching_rows` — nothing matched; no job was queued.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "400": {
                        "description": "Two sources sent, a filter/polygon list, unknown filters, or maxCredits too low.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "404": {
                        "description": "No alert or list with that id in your membership.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    }
                }
            }
        },
        "/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** — no credit check, so a file stays downloadable at a zero balance.\n\nA job that is not ready, has expired, or whose artifact cannot be read is a `409`, not a `404`. Write the poller against `409`.",
                "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"
                    },
                    "402": {
                        "description": "`subscription_required` — the bytes need a live subscription (owner ruling 2026-08-21). Polling the job metadata on `GET /exports/{id}` does not.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "404": {
                        "description": "No export job with this id in your team scope.",
                        "headers": {
                            "X-Boardwalk-Schema-Version": {
                                "$ref": "#/components/headers/BoardwalkSchemaVersion"
                            }
                        }
                    },
                    "409": {
                        "description": "The job exists but cannot be downloaded right now. `error.code` says which:\n\n* `export_not_ready` — still building. Poll `GET /exports/{id}` until `status` is `ready`.\n* `export_expired` — the file is no longer stored. Re-run the search with `format=csv`.\n* `export_unavailable` — built, but its artifact could not be read back, so it was never delivered. `error.details.creditsRefunded` states what was returned to the pool.",
                        "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 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-27"
                }
            }
        },
        "parameters": {
            "Representation": {
                "name": "representation",
                "in": "query",
                "required": false,
                "description": "How much of each record to return: `compact`, `standard`, `full`. Each nests inside the next. Representation does not change the record price — County, State, and National search, detail, and sync are free; Standalone API Only and the free trial are 1 credit per new or changed record. Find Contact Info is billed separately. 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",
                    "inFemaFloodZone",
                    "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. For a merged development this is reconciled across the whole family — the newest hearing of any merged record, never later than today or than your meetingDateTo bound — so it matches the product map and your date filters.",
                        "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"
                    },
                    "inFemaFloodZone": {
                        "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"
                        }
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "Where this project stands, as a stable machine token. On a merged development whose meetingDate was reconciled to a newer family hearing, this (with statusLabel and decisionBody) describes that same newest hearing, matching the product map.",
                        "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",
                    "inFemaFloodZone",
                    "propertyType",
                    "propertyTypeLabel",
                    "propertySubtype",
                    "propertySubtypeLabel",
                    "assetClass",
                    "assetClassLabel",
                    "landUses",
                    "status",
                    "statusLabel",
                    "statusSummary",
                    "requestType",
                    "requestTypeLabel",
                    "decisionBody",
                    "caseNumbers",
                    "acreage",
                    "squareFootage",
                    "unitMix",
                    "totalUnitCount",
                    "bedroomCount",
                    "buildingStories",
                    "floorCount",
                    "buildingHeightFeet",
                    "parkingSpaces",
                    "existingZoning",
                    "proposedZoning",
                    "isRezone",
                    "constructionType",
                    "constructionTypeLabel",
                    "projectSize",
                    "projectSizeLabel",
                    "developerCompany",
                    "developerCompanyRole",
                    "developerCompanyRoleLabel",
                    "contacts",
                    "contactEnrichment",
                    "companyEnrichment",
                    "publicOfficials",
                    "contactSummary",
                    "keyFacts",
                    "evidence",
                    "summary",
                    "voteSummary",
                    "sourceDocumentUrl"
                ],
                "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. For a merged development this is reconciled across the whole family — the newest hearing of any merged record, never later than today or than your meetingDateTo bound — so it matches the product map and your date filters.",
                        "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"
                    },
                    "inFemaFloodZone": {
                        "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"
                        }
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "Where this project stands, as a stable machine token. On a merged development whose meetingDate was reconciled to a newer family hearing, this (with statusLabel and decisionBody) describes that same newest hearing, matching the product map.",
                        "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"
                    },
                    "statusSummary": {
                        "type": "string",
                        "nullable": true,
                        "description": "A sentence summarising where the project stands right now.",
                        "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"
                    },
                    "unitMix": {
                        "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/UnitMixEntry"
                        }
                    },
                    "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"
                    },
                    "projectSize": {
                        "type": "string",
                        "nullable": true,
                        "description": "How large the construction is, in the product's own vocabulary: `large`, `medium` or `small`. Null when the size could not be judged.",
                        "x-group": "construction"
                    },
                    "projectSizeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of projectSize.",
                        "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"
                    },
                    "summary": {
                        "type": "string",
                        "nullable": true,
                        "description": "The project summary shown at the top of the product's project page: what is being built, by whom, and where the approval process stands.",
                        "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"
                            }
                        ]
                    },
                    "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"
                            }
                        ]
                    },
                    "sourceDocumentUrl": {
                        "type": "string",
                        "nullable": true,
                        "description": "Direct link to the original public meeting document (usually a PDF) this record's latest extraction came from, on the jurisdiction's own site.",
                        "x-group": "documents"
                    }
                }
            },
            "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",
                    "inFemaFloodZone",
                    "propertyType",
                    "propertyTypeLabel",
                    "propertySubtype",
                    "propertySubtypeLabel",
                    "assetClass",
                    "assetClassLabel",
                    "landUses",
                    "classifications",
                    "tags",
                    "status",
                    "statusLabel",
                    "statusSummary",
                    "requestType",
                    "requestTypeLabel",
                    "decisionBody",
                    "caseNumbers",
                    "isAppeal",
                    "nextHearingDate",
                    "acreage",
                    "squareFootage",
                    "unitMix",
                    "totalUnitCount",
                    "affordableUnits",
                    "bedroomCount",
                    "lotCount",
                    "buildingCount",
                    "buildingStories",
                    "floorCount",
                    "buildingHeightFeet",
                    "parkingSpaces",
                    "amenities",
                    "existingZoning",
                    "proposedZoning",
                    "isRezone",
                    "variancesRequested",
                    "constructionType",
                    "constructionTypeLabel",
                    "projectSize",
                    "projectSizeLabel",
                    "likelyTrades",
                    "developerCompany",
                    "developerCompanyRole",
                    "developerCompanyRoleLabel",
                    "contacts",
                    "contactEnrichment",
                    "companyEnrichment",
                    "publicOfficials",
                    "contactSummary",
                    "keyFacts",
                    "evidence",
                    "conditionsOfApproval",
                    "summary",
                    "decisions",
                    "voteSummary",
                    "sourceDocumentUrl",
                    "originalRawText",
                    "originalRawTextTruncated"
                ],
                "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. For a merged development this is reconciled across the whole family — the newest hearing of any merged record, never later than today or than your meetingDateTo bound — so it matches the product map and your date filters.",
                        "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"
                    },
                    "inFemaFloodZone": {
                        "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"
                        }
                    },
                    "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. On a merged development whose meetingDate was reconciled to a newer family hearing, this (with statusLabel and decisionBody) describes that same newest hearing, matching the product map.",
                        "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"
                    },
                    "statusSummary": {
                        "type": "string",
                        "nullable": true,
                        "description": "A sentence summarising where the project stands right now.",
                        "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"
                    },
                    "unitMix": {
                        "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/UnitMixEntry"
                        }
                    },
                    "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": "Total lots in the subdivision or plat, summed across every stated lot group. Open-space and common-area rows are not lots and are not counted.",
                        "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"
                    },
                    "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"
                    },
                    "projectSize": {
                        "type": "string",
                        "nullable": true,
                        "description": "How large the construction is, in the product's own vocabulary: `large`, `medium` or `small`. Null when the size could not be judged.",
                        "x-group": "construction"
                    },
                    "projectSizeLabel": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable form of projectSize.",
                        "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"
                        }
                    },
                    "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": "The project summary shown at the top of the product's project page: what is being built, by whom, and where the approval process stands.",
                        "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"
                            }
                        ]
                    },
                    "sourceDocumentUrl": {
                        "type": "string",
                        "nullable": true,
                        "description": "Direct link to the original public meeting document (usually a PDF) this record's latest extraction came from, on the jurisdiction's own site.",
                        "x-group": "documents"
                    },
                    "originalRawText": {
                        "type": "string",
                        "nullable": true,
                        "description": "The transcribed text of the portion of the public record this project was extracted from — the project's own agenda-item slice where the document covers many items, otherwise the full document text.",
                        "x-group": "documents"
                    },
                    "originalRawTextTruncated": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "True when originalRawText was cut at the per-record character cap.",
                        "x-group": "documents"
                    }
                }
            },
            "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
                    }
                }
            },
            "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
                    }
                }
            },
            "UnitMixEntry": {
                "type": "object",
                "title": "Unit Mix",
                "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-27"
                    },
                    "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-27"
                    },
                    "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 AI-search job metadata, including 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. A paid page is delivered whole or refused whole, never trimmed — a page the balance 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."
                    }
                }
            },
            "EnrichmentAllowance": {
                "type": "object",
                "description": "The monthly enrichment allowance — the meter behind the free find-contact-info flow. `limit` null means the plan carries no explicit cap. The same meter appears on `GET /account/credits` under `data.enrichment`, where it is spelled `monthlyAttemptsLimit` / `attemptsUsed` / `attemptsRemaining` / `resetsAt`; and on `GET /enrichments/{id}` as the two flat counters `allowanceUsed` and `allowanceRemaining`.",
                "properties": {
                    "used": {
                        "type": "integer"
                    },
                    "limit": {
                        "type": "integer",
                        "nullable": true
                    },
                    "remaining": {
                        "type": "integer",
                        "nullable": true
                    },
                    "resetsAt": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "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. Representation does not change the record price: County, State, and National are free; Standalone API Only and the free trial are 1 credit per new or changed record. Find Contact Info is billed separately. Also accepted as a `?representation=` query parameter."
                    },
                    "deliveryMode": {
                        "type": "string",
                        "enum": [
                            "all"
                        ],
                        "default": "all",
                        "description": "Only `all` is accepted on AI search; `deliveryMode=new` is supported on `GET /projects/search`. 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 1,000 on the AI-search job route."
                    },
                    "sort": {
                        "type": "string",
                        "enum": [
                            "meeting_date",
                            "updated_at",
                            "data_richness"
                        ],
                        "default": "meeting_date"
                    },
                    "order": {
                        "type": "string",
                        "enum": [
                            "asc",
                            "desc"
                        ],
                        "default": "desc"
                    },
                    "states": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "oneOf": [
                                {
                                    "type": "integer",
                                    "minimum": 1
                                },
                                {
                                    "type": "string",
                                    "minLength": 1
                                }
                            ]
                        },
                        "description": "Optional state filter. Integer IDs, USPS abbreviations (`UT`), or names (`Utah`). Same vocabulary as `GET /projects/search`."
                    },
                    "stateIds": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "oneOf": [
                                {
                                    "type": "integer",
                                    "minimum": 1
                                },
                                {
                                    "type": "string",
                                    "minLength": 1
                                }
                            ]
                        },
                        "description": "Alias of `states`. Integer IDs, USPS abbreviations, or names."
                    },
                    "stateId": {
                        "oneOf": [
                            {
                                "type": "integer",
                                "minimum": 1
                            },
                            {
                                "type": "string",
                                "minLength": 1
                            }
                        ],
                        "description": "Optional single state: ID, USPS abbreviation, or name."
                    },
                    "state": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "oneOf": [
                                {
                                    "type": "integer",
                                    "minimum": 1
                                },
                                {
                                    "type": "string",
                                    "minLength": 1
                                }
                            ]
                        },
                        "description": "Legacy alias for `states`."
                    },
                    "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 and live trials. 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
                            }
                        }
                    },
                    "notify": {
                        "type": "object",
                        "additionalProperties": false,
                        "description": "Async jobs only. Controls the settlement email sent to the submitter's account address when the job reaches a terminal state (completed, partial, failed, or cancelled). The email is a pointer — counts, credits, and the poll URL, never record data. Unknown keys return `400`.",
                        "properties": {
                            "email": {
                                "type": "boolean",
                                "default": true,
                                "description": "Send the settlement email. Defaults to true."
                            }
                        }
                    }
                }
            },
            "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"
                            }
                        }
                    }
                }
            },
            "AiSearchJobCancel": {
                "type": "object",
                "description": "Body for `DELETE /projects/ai-search/jobs/{id}` — the job's state after the cancellation request was applied.",
                "properties": {
                    "requestId": {
                        "type": "integer"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "completed",
                            "partial",
                            "failed",
                            "cancelled",
                            "expired"
                        ]
                    },
                    "cancelRequested": {
                        "type": "boolean",
                        "description": "True once a cancel has been recorded; the worker honours it at the next batch boundary."
                    },
                    "creditsReserved": {
                        "type": "integer"
                    },
                    "creditsCharged": {
                        "type": "integer",
                        "nullable": true
                    },
                    "creditsRefunded": {
                        "type": "integer",
                        "description": "Credits refunded by THIS request. A queued job refunds its full reservation here; a running job refunds nothing yet — its settlement true-up refunds the unused remainder."
                    },
                    "pollUrl": {
                        "type": "string"
                    }
                }
            },
            "CsvExportJobAccepted": {
                "type": "object",
                "description": "HTTP 202 body for `POST /exports` and `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_matching_rows",
                            "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 `GET /projects/sync` records only — every other record route ships the four-key `DeliveryState` (`alreadyExported`, `updatedSinceExport`, `lastExportedAt`, `billed`) and no revision — so a sync mirror can dedupe locally without trusting our classification at all. Computed over the record BEFORE merged-family reconciliation, so your date window can never move a revision or make an unchanged record bill as changed; a `meetingDate` entry in `changes[]` likewise reports raw movement, so its from/to values can differ from the reconciled `meetingDate` served on the same record."
                    },
                    "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-27"
                    },
                    "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": "True when the count was exact — the real charge can only come in lower than the quote, never higher. When the scan hit its ceiling (`matchCountIsExact: false`) the quote priced a prefix of the match and is not a ceiling; this field is false and says so."
                                    },
                                    "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 when a metered page costs more than the balance has left.",
                                "properties": {
                                    "policy": {
                                        "type": "string",
                                        "enum": [
                                            "refuse",
                                            "trial_truncate"
                                        ],
                                        "description": "A paid page is delivered whole or refused whole — never trimmed; trial keys truncate the page 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-27"
                            },
                            "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-27"
                            },
                            "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."
                            },
                            "enrichment": {
                                "type": "object",
                                "nullable": true,
                                "description": "The monthly enrichment allowance — the same meter `POST /enrichments` reports as `EnrichmentAllowance`, spelled with longer key names here. Null when enrichment is not wired for this environment.",
                                "properties": {
                                    "monthlyAttemptsLimit": {
                                        "type": "integer",
                                        "nullable": true,
                                        "description": "Null means the plan carries no explicit cap."
                                    },
                                    "attemptsUsed": {
                                        "type": "integer"
                                    },
                                    "attemptsRemaining": {
                                        "type": "integer",
                                        "nullable": true
                                    },
                                    "resetsAt": {
                                        "type": "string",
                                        "format": "date-time"
                                    }
                                }
                            }
                        }
                    },
                    "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "PaymentRequired": {
                "description": "Subscription missing, credits exhausted, or the page this request would deliver costs more than the balance has left.\n\n* `subscription_required` — no active paid plan or trial behind this key.\n* `credits_exhausted` — the balance cannot cover even one record and this response would have billed at least one. Re-reads of unchanged records you already own bill 0 and are still served at 0 balance. Paid balances refill on the 1st; trial credits never do.\n* `insufficient_credits` — the balance has credits left, but fewer than this page would cost. A page is delivered whole or refused whole — never trimmed — so **no records are returned and nothing is charged**. `details.quote` states the page's cost, what remains, `affordableRecordCount` — the `limit` to retry with — and a free `countUrl` that re-prices the whole match set. Free-trial pages are truncated instead of refused here — see `meta.trialTruncation`.\n* `enrichment_requires_paid_plan` — `include=contacts` (Find Contact Info) needs a paid plan or a live trial. Record credits may still remain. Drop the parameter, start a trial, 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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            },
            "IdempotencyConflict": {
                "description": "The `Idempotency-Key` on this request conflicts with an earlier one. `error.code` says which:\n\n* `idempotency_key_reuse` — this key was already used for a **different** request. `details.originalEndpoint` and `details.originalCreatedAt` name the request it belongs to. Mint a new key per distinct request; reuse a key only to retry the request it was minted for.\n* `idempotency_in_flight` — the original request with this key is still running. Retry in a moment to receive its result; you will not be charged twice. Carries a `Retry-After` header, echoed as `details.retryAfterSeconds`.\n\nBoth name `Idempotency-Key` in `error.param`. Nothing is delivered and nothing is charged.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ApiError"
                        },
                        "example": {
                            "error": {
                                "code": "idempotency_key_reuse",
                                "message": "This Idempotency-Key was already used for a different request. Generate a new key for each distinct request; reuse a key only to retry the request it was minted for.",
                                "param": "Idempotency-Key",
                                "details": {
                                    "originalEndpoint": "api_v1_projects_search",
                                    "originalCreatedAt": "2026-08-27T14:02:11+00:00"
                                },
                                "docsUrl": "https://boardwalkai.com/docs/api/errors#idempotency_key_reuse",
                                "requestId": "req_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                }
            },
            "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_01K1QF3M0000EXAMPLE0001"
                            }
                        }
                    }
                },
                "headers": {
                    "X-Boardwalk-Schema-Version": {
                        "$ref": "#/components/headers/BoardwalkSchemaVersion"
                    }
                }
            }
        }
    }
}
