Skip to main content

Budgets, quotes and the 402

Count is always free. On County, State, and National, search is free too. On API Only and the trial, count also prices the set before you page.

Count is always free. It tells you how many distinct projects match. On County, State, and National, search is also free, so you use count to size the set — not to decide whether you can afford it. On API Only and the free trial, the same quote prices the set: those plans charge 1 credit per new record, never overshoot the balance, and never trim a page. A refused page arrives with a quote that says what to retry with.

The free quote

Price a broad query — before spending anything

bash
curl 'https://api.boardwalkai.com/api/v1/projects/count?states=UT&assetClasses=Apartment%20Building&dateRange=all' \
  -H 'Authorization: Bearer bwk_live_YOUR_KEY'

Response · HTTP 200

json
{
  "data": {
    "matchCount": 5000,
    "matchCountIsExact": true,
    "matchCountBasis": "enumerated",
    "countedAs": "distinct_projects",
    "collapseApplied": true,
    "duplicatesCollapsed": 0,
    "scanCeiling": 10000,
    "billable": {
      "records": 5000,
      "credits": 0,
      "creditRate": 0,
      "isUpperBound": true,
      "nonBillable": {
        "alreadyDeliveredUnchanged": 0,
        "ledgerApplied": true
      }
    },
    "affordability": {
      "affordable": true,
      "blockReason": null,
      "shortfallCredits": 0,
      "maxAffordableRecords": 9223372036854776000,
      "boundBy": "period_balance",
      "unlimited": false
    },
    "ordering": {
      "sort": "meetingDate",
      "order": "desc",
      "tiebreak": null,
      "meaning": "Most recent meeting evidence first — the date of the meeting the record was extracted from, not when Boardwalk ingested it and not when the project was created."
    },
    "truncation": {
      "policy": "refuse",
      "wouldTruncate": false,
      "deliverableRecords": null,
      "explanation": "The whole match set fits inside the remaining balance: page through the metered route and every page will be delivered in full until the set is exhausted."
    }
  },
  "meta": {
    "schemaVersion": "2026-09-16",
    "representation": "standard",
    "deliveryMode": "all",
    "credits": {
      "limit": 500,
      "used": 0,
      "remaining": 500,
      "charged": 0,
      "periodStart": "2026-08-01",
      "periodEnd": "2026-08-31",
      "isTeamPool": true
    },
    "appliedFilters": {
      "states": [
        1
      ],
      "assetClasses": [
        "Apartment Building"
      ],
      "dateRange": "all"
    },
    "appliedDefaults": [
      "taxonomyMatchMode=primary_only",
      "includeGovernmentDecisions=false",
      "leadTypes=private",
      "sort=meetingDate",
      "order=desc"
    ],
    "resolvedFrom": {
      "states": [
        {
          "input": "UT",
          "id": 1
        }
      ]
    },
    "warnings": []
  },
  "links": {
    "self": "https://api.boardwalkai.com/api/v1/projects/count?states=UT&assetClasses=Apartment%20Building&dateRange=all",
    "search": "https://api.boardwalkai.com/api/v1/projects/search?states=UT&assetClasses=Apartment%20Building&dateRange=all",
    "docs": "https://boardwalkai.com/docs/api/budgets/"
  }
}

The response shape on this page is the one the endpoint builds — the keys, their nesting and their types are asserted against the shipping code by a test. The numbers inside it are the scenario being walked through, not a measurement of the corpus.

Credit costFree — 0 creditsFree, always, including when your balance is zero. How many projects match. On API Only and the trial it also prices the set; on County, State, and National, search is free.

Reading a quote

FieldWhat it tells you
matchCountHow many distinct projects match. Post-collapse, so it counts developments, not filings.
matchCountIsExactfalse when the index held more rows than one request may read, and the true total is higher. scanCeiling is that row budget — not a project count, and not a bound on matchCount.
billable.recordsHow many of those you would actually be charged for. Lower than matchCount when you already hold some unchanged.
billable.creditsThe cost. records × creditRate.
billable.isUpperBoundtrue when the count was exact — the real charge can only be lower. When the scan hit its ceiling (matchCountIsExact: false) the quote priced a prefix of the match and is not a ceiling, and this field says so.
affordability.affordableWhether the whole remaining set fits the balance. false does not mean your next search call fails — you can still page and collect maxAffordableRecords records; the first page that does not fit is refused.
affordability.shortfallCreditsHow many more you would need.
affordability.maxAffordableRecordsHow many records the balance can pay for right now.
truncation.policyrefuse on a paid plan, trial_truncate on a trial key. It names the page rule — what happens to a page the balance cannot pay for — while the affordability block above is set-scoped.
orderingThe sort that would be applied, so "the first 500" is a defined set rather than an arbitrary one.

The refusal

What a request you cannot afford looks like

bash
curl 'https://api.boardwalkai.com/api/v1/projects/search?states=UT&assetClasses=Apartment%20Building&dateRange=all&limit=100' \
  -H 'Authorization: Bearer bwk_live_YOUR_KEY'

Response · HTTP 402

json
{
  "error": {
    "code": "insufficient_credits",
    "message": "This request would deliver 100 records and cost 100 credits. You have 40.",
    "param": null,
    "details": {
      "quote": {
        "matchCount": 5000,
        "matchCountIsExact": true,
        "creditRate": 0,
        "creditsRequired": 100,
        "creditsRemaining": 40,
        "affordableRecordCount": 0,
        "countUrl": "https://api.boardwalkai.com/api/v1/projects/count?states=UT&assetClasses=Apartment%20Building&dateRange=all"
      }
    },
    "docsUrl": "https://boardwalkai.com/docs/api/errors#insufficient_credits",
    "requestId": "req_01K1QF3M0000EXAMPLE0001"
  }
}

The response shape on this page is the one the endpoint builds — the keys, their nesting and their types are asserted against the shipping code by a test. The numbers inside it are the scenario being walked through, not a measurement of the corpus.

insufficient_credits fires when the page a request would deliver costs more than the balance has left. error.details.quote prices two different things and says which is which: matchCount is the whole match set, courtesy-priced by the same arithmetic as the count endpoint, so the number you narrow against and the number a refusal names cannot disagree; creditsRequired is the billable cost of the refused page, never the set's. affordableRecordCount is the limit to retry with, and countUrl is a free URL that re-prices this exact filter set — which is what lets an agent recover without a human.

Why not just deliver what I can afford?

Because a page trimmed to a budget would be indistinguishable from a page the data made short. A customer who asks for 100 records and silently receives 40 — because that was all the balance covered — concludes our coverage is thin, builds on a partial dataset, and finds out months later. Refusing the page whole is louder and cheaper for everyone, and it keeps a promise worth building on: paid pages are never trimmed, so a short page always means that is all that matched — never that your balance ran out. Trial keys are the exception, and they say so explicitly in meta.trialTruncation.

Ready to make a call?

A free Boardwalk trial includes API access, 50 record-export credits (search, CSV, MCP), and 5 Find Contact Info lookups. Counting, taxonomy, location lookups and the analytics plane cost nothing, so you can evaluate the data before you spend a credit.