The same numbers behind the MN Rent Explorer, as JSON. Five endpoints, served as static files from the edge, CORS open to any origin, cached for a day. No key, no rate limit, no signup. Licensed CC BY 4.0, so attribution is the only condition.
| Path | Returns |
|---|---|
| /api/v1/index.json | Every one of the 914 ZIP codes in one array: fair market rent by bedroom, year over year change, latest market rent, spread, and the voucher competitive flag. |
| /api/v1/zip/{zip}.json | One ZIP code in full: the fair market rent series by fiscal year and bedroom count, the monthly market rent series, ACS medians where published, and the six nearest ZIP codes. |
| /api/v1/county/{slug}.json | One of the 87 counties: medians, ZIP count, and a row per ZIP code. Slug is the lowercase county name with non alphanumeric runs collapsed to one hyphen, for example st-louis. |
| /api/v1/section-8.json | The 172 ZIP codes carrying both a fair market rent and a market rent, with the spread in dollars and percent and a summary block. |
| /api/v1/meta.json | Counts, source vintages, the license, the citation string, and the endpoint list. Fetch this first to see whether anything changed. |
Base URL is https://pencilwrite.com. Every response carries a meta object with the license, the attribution string, source vintages, the generation timestamp, and the schema version. The full machine readable contract is at /openapi.json.
curl -s https://pencilwrite.com/api/v1/zip/55401.json | jq '.fmr.br2' curl -s https://pencilwrite.com/api/v1/section-8.json | jq '.summary' curl -s https://pencilwrite.com/api/v1/index.json \ | jq '[.zips[] | select(.voucher_competitive == true)] | length'
# Python
import requests
z = requests.get("https://pencilwrite.com/api/v1/zip/55401.json", timeout=10).json()
print(z["city"], z["fmr"]["br2"], z["meta"]["attribution"])
// JavaScript
const r = await fetch("https://pencilwrite.com/api/v1/section-8.json");
const {summary, rows} = await r.json();
console.log(summary.voucher_competitive_count, rows.length);Files are immutable between regenerations and served with a one day cache. Poll /api/v1/meta.json and compare generated_at rather than refetching every ZIP.
Published under CC BY 4.0. Commercial use is fine. Cite as: Pencilwrite MN Rent Data, pencilwrite.com/rents/.
Read the methodology before you build on these numbers. Fair market rent is a 40th percentile estimate on a federal fiscal year and the Zillow index is a smoothed asking rent index across all unit sizes. Neither is a rent quote for any address. Underlying sources keep their own terms.
An MCP server exposing the same data to agents is coming soon at mcp.pencilwrite.com. Until then, agents can read /llms.txt for the short index or /llms-full.txt for the full plain text summary, or call these endpoints directly. Every payload names its source vintages and carries the attribution string in meta.attribution.
Pencilwrite turns an address, a price, and these rents into a full underwrite, cap rate, cash-on-cash, DSCR, true ROE, taxes, and an offer you can send. Limited beta access spots open. Sign up for the beta, opening in the next two months. Free.