API
Prepaid public REST — POST|GET /api/v1/sites/check is the priced unit. Coverage and usage are free. Keys are bk_live_. CORS stays off.
The public REST contract is a prepaid site check plus the two free reads a developer needs around it. There is no monthly API plan.
Start with the developer quickstart:
load credit, mint a bk_live_ key at /settings/developer, call
/api/v1/sites/check, and read the usage receipt.
Priced unit
POST|GET /api/v1/sites/check is the only metered route. The billable unit
is a sourced result, not a transport call. Uncovered sites return HTTP 202
with answered: false and a receipt proving charged: false, reason: 'not_covered'.
Price: $0.10 USD per sourced check. Minimum load: $10 USD. A free account includes 10 site lookups a month, including headless use, so a $10 load is 110 checks in month one.
The envelope is { schemaVersion, checkId, answered, normalizedAddress, coverage, parcel, zoning, facts, usage, generatedAt }. Every priced response
also stamps X-Bucky-Receipt-* headers, including 304 and 402.
Free reads
| Route | Auth | Notes |
|---|---|---|
GET /api/v1/coverage/divisions/{slug} | Anonymous | Count-only coverage card. Not a coordinate lookup — /api/geo/coverage-status already does that. |
GET /api/v1/usage/balance | Session, user JWT, or usage:read key | Remaining prepaid balance. A missing account is a zero balance, not a 404. |
POST /api/v1/addresses/suggest | Optional key (site:read) | Free. |
POST /api/v1/addresses/retrieve | Optional key (site:read) | Free. |
What a key cannot do
sites/contextstays session/JWT in M1 — not key-eligible, so callers cannot arbitrage a free context against a priced check.sites/resolveis first-party only. It persists afeasibility_sitesrow. A key receives403 FORBIDDEN.feasibility/analyses*is first-party only. A key receives402 SCOPE_UNAVAILABLEnaming the unsoldanalysis:writescope.research/*is denylisted from the public OpenAPI artifact. Those handlers are admin-only.
Redaction
ownershipHint and rawCityData are never returned to a key, regardless of
scope. If ownership is ever sold it is a separately-priced parcel:owner scope
with its own consent review. See
docs/api/public-api-boundary.md.
Authentication
Authorization: Bearer bk_live_… (or bk_test_…). Scopes: site:read,
usage:read. CORS stays off — a key is a server-side credential and must not
ship to a browser. Session cookies and Supabase user JWTs still work on v1;
programmatic JWTs need Professional. Keys skip that subscription gate and debit
prepaid credit.
Match auth errors on code: AUTH_REQUIRED and INVALID_API_KEY are 401;
INSUFFICIENT_SCOPE is 403. Details live in
docs/api/v1-auth.md.
OpenAPI
The machine-readable description is an OpenAPI 3.1 document:
https://buckybuild.com/openapi.jsonThe same document is served at /api/openapi, and both are advertised as
service-desc in /.well-known/api-catalog.
It is a curated subset of the internal surface — default-deny — covering
/api/v1 (site check, coverage, usage, addresses) and /api/marketplace/v2.
Every operation carries a unique operationId, typed parameters, and a
documented error schema.
Versioning, errors, and rate limits
- Versioning is in the URL path (
/api/v1,/api/marketplace/v2). There is no unversioned public surface. Within a version, changes are additive only. Retirement is signalled withDeprecation(RFC 9745) andSunset(RFC 8594) response headers. - Errors return a consistent JSON envelope:
error,code,category,status,retryable,supportId,requestId. Match oncode, never on the message text. - Rate limits are reported as
RateLimitandRateLimit-PolicyalongsideRateLimit-Limit/-Remaining/-Reset. A 429 carriesRetry-After. The ledger is the spend bound — do not treat the per-lambda bucket as abuse control.
Use this today
- HTTP — this page and the developer quickstart.
- MCP — tools for agents. See MCP.
- CLI — product and scripting workflows. See CLI.
Building an integration now? Start with the developer quickstart. Use MCP if you are wiring an AI agent, or the CLI for scripting.
Last updated on