ZoningVerdict

Developer docs

Published zoning content as structured data: municipalities, districts, rules, and reviewed Q&A, every rule with its ordinance citation and source link, plus address-to-district resolution where a public GIS path exists.

Records tell you what's on file; ZoningVerdict tells you what the ordinance actually says, independently verified, with the citation.

ZoningVerdict summarizes public zoning regulations for information purposes. It is not legal advice, professional architectural or engineering services, or a substitute for confirmation with the municipality. Regulations change; verify before acting.

Every response carries that disclaimer and the content pack's last-reviewed date and version, so agents can cite and cache coherently. API response disclaimer fields link to /terms (v0-draft). Draft content never appears through any path.

Authentication

The municipalities and districts endpoints are free and keyless. Rules, questions, and parcel resolve need a key from /api-access (self-serve, shown once), sent as a Bearer token or an X-Api-Key header. Each key includes 100 free calls per month; after that, $0.10 per rules or questions call and $0.25 per parcel resolve, billed through Stripe.

OpenAPI

The schema is served at https://zoningverdict.com/api/v1/openapi.json.

Agent discovery

Machine-readable instructions at /skill.md, A2A discovery at /.well-known/agent-card.json, and the x402 paid-tool manifest at /.well-known/ai-tool/index.json. Terms: https://zoningverdict.com/terms.

Try it

Live calls against the real API. Discovery is free and keyless; rules and questions have a 3-call daily keyless trial per municipality. Parcel resolve returns the real 402 from the first unsigned request. Errors are included; nothing is staged.

GET /api/v1/districts?municipality=

MCP: list_districts {"municipality":""}

Endpoints

GET /api/v1/municipalities

Published coverage with pack version and last-reviewed date. Free.

curl https://zoningverdict.com/api/v1/municipalities

GET /api/v1/coverage/check?q=

Coverage preflight for an address or municipality. Free; does not identify a district.

curl "https://zoningverdict.com/api/v1/coverage/check?q=1000%20Rochester%20Hills%20Dr%2C%20Rochester%20Hills%2C%20MI"

GET /api/v1/districts?municipality=

District codes, names, and summaries for one municipality. Free.

curl "https://zoningverdict.com/api/v1/districts?municipality=rochester-hills"

GET /api/v1/changelog

Content changelog: publications, pack updates, and published rule changes, newest first. Free.

curl https://zoningverdict.com/api/v1/changelog

GET /api/v1/rules?municipality=&district=&topic=

Structured rules with citations and source URLs. Metered.

curl -H "Authorization: Bearer zvk_..." \
  "https://zoningverdict.com/api/v1/rules?municipality=rochester-hills&district=R-2&topic=fences"

GET /api/v1/questions?municipality=&topic=

Reviewed question-and-answer pairs with citations. Metered.

curl -H "Authorization: Bearer zvk_..." \
  "https://zoningverdict.com/api/v1/questions?municipality=rochester-hills&topic=adu"

POST /api/v1/parcel/resolve

Address to municipality and district, lookup method disclosed. x402 pay-per-call from the first unsigned request; run the free coverage preflight first.

curl -X POST https://zoningverdict.com/api/v1/parcel/resolve \
  -H "Authorization: Bearer zvk_..." -H "content-type: application/json" \
  -d '{"address": "1000 Rochester Hills Dr, Rochester Hills, MI"}'

Recommended flow for agents

Never guess district codes: coverage and listing calls are free, then the paid address resolver identifies the district. Every empty result carries a note naming the valid district codes or covered topics, so the next call can succeed.

# Address-first (the usual case)
1. GET  /api/v1/coverage/check?q=...                 -> covered? topics + freshness
2. POST /api/v1/parcel/resolve {"address": "..."}   -> paid municipality + district_code
3. GET  /api/v1/rules?municipality=...&district=... -> rules with citations
4. GET  /api/v1/questions?municipality=...          -> reviewed Q&A

# No address? Discover, then fetch (discovery is free and keyless)
1. GET /api/v1/municipalities                  -> covered slugs
2. GET /api/v1/districts?municipality=...      -> valid district codes
3. GET /api/v1/rules?municipality=...&district=...

Same flow over MCP: check_coverage -> resolve_parcel_district -> get_district_rules,
or check_coverage -> list_municipalities -> list_districts -> get_district_rules.

MCP server

The same content is exposed as MCP tools — check_coverage, list_municipalities, list_districts, get_district_rules, ask_zoning_question, and resolve_parcel_district — over the streamable HTTP transport. The coverage and listing tools are free and keyless. Every response carries the disclaimer, pack version, last-reviewed date, and ordinance source link. The paid property brief is deliberately not an MCP tool: the brief stays a human-purchase surface.

Endpoint:  https://zoningverdict.com/api/mcp
Auth:      Authorization: Bearer zvk_...   (same keys as the REST API)
Trial:     rules and questions only, 3 calls per day per municipality
Free:      check_coverage, list_municipalities, and list_districts never count

Agent payments (x402)

Agents can also pay per call, no key or account needed. A keyless rules or questions call gets 3 free calls per day per municipality. Parcel resolve is pay-per-call from the first unsigned request; use the free coverage preflight before it. When payment is due, the endpoint returns HTTP 402 with a PAYMENT-REQUIRED header carrying x402 protocol version 2 payment requirements: $0.01 in USDC on Base, exact scheme. Retry with a PAYMENT-SIGNATURE header from any x402 v2 client; the settlement transaction comes back in the PAYMENT-RESPONSE header. Keyless x402 is the lowest per-call rate today; keys add 100 free calls per month, predictable Stripe billing, and higher rate limits. Flat monthly plans with volume pricing are coming.

# One paid call with the x402 fetch wrapper (@x402/fetch):
Price:     $0.01 per call, USDC on Base
Endpoints: /api/v1/rules, /api/v1/questions, /api/v1/parcel/resolve
Flow:      request -> 402 + PAYMENT-REQUIRED -> sign -> retry with
           PAYMENT-SIGNATURE -> 200 + PAYMENT-RESPONSE (settlement)

Limits

Change monitoring

Every pack carries a version and last-reviewed date, and the ordinance behind it is watched for amendments. A $49/month watch emails you when a human-reviewed rule change is published for a municipality — citation, date, and pack version included. Webhook delivery and an MCP create_watch tool are planned; watch mail is the v1 lane. Data vintage is public: per-municipality freshness on the coverage page and content events at /api/v1/changelog, both free and keyless.

Need a municipality we do not cover?

City Unlock records the demand for it. When a municipality enters the reviewed pipeline, it runs from the official ordinance through independent verification and live GIS testing (see how we verify a municipality). The result becomes public API coverage maintained under our amendment watch.