{
  "openapi": "3.1.0",
  "info": {
    "title": "Pencilwrite Minnesota Rent Data API",
    "version": "1.0.0",
    "summary": "Free JSON rent data for every Minnesota ZIP code and county.",
    "description": "HUD Small Area Fair Market Rents, the Zillow Observed Rent Index, and Census ACS median gross rent for Minnesota, served as static JSON. No key, no rate limit, CORS open to any origin. Fair Market Rent is a 40th percentile estimate published on a federal fiscal year basis and the Zillow Observed Rent Index is a smoothed index of asking rents across all unit sizes. Neither is a rent quote for any address. Methodology: https://pencilwrite.com/rents/methodology/",
    "termsOfService": "https://pencilwrite.com/privacy",
    "contact": {
      "name": "Pencilwrite",
      "email": "ruffininninc@gmail.com",
      "url": "https://pencilwrite.com/developers/"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    }
  },
  "servers": [
    {
      "url": "https://pencilwrite.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Developer docs and methodology",
    "url": "https://pencilwrite.com/developers/"
  },
  "paths": {
    "/api/v1/index.json": {
      "get": {
        "operationId": "listZips",
        "summary": "Every Minnesota ZIP code, 914 rows.",
        "description": "One row per ZIP with the latest fiscal year FMR by bedroom, year over year change, latest market rent, spread, and the voucher competitive flag.",
        "responses": {
          "200": {
            "description": "The full ZIP index.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZipIndex"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/zip/{zip}.json": {
      "get": {
        "operationId": "getZip",
        "summary": "One ZIP code in full.",
        "parameters": [
          {
            "name": "zip",
            "in": "path",
            "required": true,
            "description": "Five digit Minnesota ZIP code.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$"
            },
            "example": "55401"
          }
        ],
        "responses": {
          "200": {
            "description": "Full history and context for one ZIP code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZipDetail"
                }
              }
            }
          },
          "404": {
            "description": "No SAFMR data for that ZIP code."
          }
        }
      }
    },
    "/api/v1/county/{slug}.json": {
      "get": {
        "operationId": "getCounty",
        "summary": "One county, 87 available.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Lowercase county name, non alphanumeric runs collapsed to one hyphen. St. Louis becomes st-louis.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            },
            "example": "hennepin"
          }
        ],
        "responses": {
          "200": {
            "description": "County medians and a row per ZIP code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountyDetail"
                }
              }
            }
          },
          "404": {
            "description": "No county with that slug."
          }
        }
      }
    },
    "/api/v1/section-8.json": {
      "get": {
        "operationId": "getSectionEight",
        "summary": "FMR versus market rent spread, 172 ZIP codes.",
        "description": "Only ZIP codes carrying both a HUD FMR and a Zillow ZORI value appear.",
        "responses": {
          "200": {
            "description": "The spread table and summary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectionEight"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/meta.json": {
      "get": {
        "operationId": "getMeta",
        "summary": "Counts, source vintages, license, endpoint list.",
        "description": "Poll this and compare generated_at rather than refetching every ZIP.",
        "responses": {
          "200": {
            "description": "Dataset metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetaDoc"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Meta": {
        "type": "object",
        "required": [
          "license",
          "license_url",
          "attribution",
          "sources",
          "generated_at",
          "schema_version",
          "docs"
        ],
        "properties": {
          "license": {
            "type": "string",
            "example": "CC BY 4.0"
          },
          "license_url": {
            "type": "string",
            "format": "uri"
          },
          "attribution": {
            "type": "string",
            "example": "Pencilwrite MN Rent Data, pencilwrite.com/rents/"
          },
          "sources": {
            "type": "object",
            "properties": {
              "hud_safmr": {
                "type": "string",
                "example": "FY2026"
              },
              "zori": {
                "type": "string",
                "example": "2026-07"
              }
            }
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "schema_version": {
            "type": "string",
            "example": "1.0"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "IndexZip": {
        "type": "object",
        "properties": {
          "zip": {
            "type": "string",
            "example": "55401"
          },
          "city": {
            "type": "string"
          },
          "county": {
            "type": "string"
          },
          "county_slug": {
            "type": "string"
          },
          "fmr": {
            "type": "object",
            "description": "HUD Fair Market Rent in whole dollars by bedroom count, br0 is a studio.",
            "properties": {
              "br0": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "br1": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "br2": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "br3": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "br4": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          },
          "fmr2_yoy_pct": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent change in the 2 bedroom FMR against the prior fiscal year."
          },
          "zori_latest": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "month": {
                "type": "string",
                "example": "2026-07"
              },
              "rent": {
                "type": "integer"
              }
            }
          },
          "spread": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Market rent minus 2 bedroom FMR, dollars. Null when the ZIP has no ZORI series."
          },
          "spread_pct": {
            "type": [
              "number",
              "null"
            ]
          },
          "voucher_competitive": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "True when the 2 bedroom FMR meets or exceeds market rent."
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "lastmod": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "ZipIndex": {
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "count": {
            "type": "integer"
          },
          "zips": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndexZip"
            }
          }
        }
      },
      "ZipDetail": {
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "zip": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "county": {
            "type": "string"
          },
          "county_slug": {
            "type": "string"
          },
          "metro": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "lastmod": {
            "type": "string",
            "format": "date"
          },
          "fmr_latest_fy": {
            "type": "integer",
            "example": 2026
          },
          "fmr_by_fy": {
            "type": "object",
            "description": "Keyed by federal fiscal year as a string.",
            "additionalProperties": {
              "type": "object",
              "description": "HUD Fair Market Rent in whole dollars by bedroom count, br0 is a studio.",
              "properties": {
                "br0": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "br1": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "br2": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "br3": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "br4": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          },
          "fmr2_yoy_pct": {
            "type": [
              "number",
              "null"
            ]
          },
          "zori_monthly": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "month": {
                  "type": "string"
                },
                "rent": {
                  "type": "number"
                }
              }
            }
          },
          "zori_latest": {
            "type": [
              "object",
              "null"
            ]
          },
          "acs": {
            "type": [
              "object",
              "null"
            ],
            "description": "Census ACS medians for the ZCTA, present only where published."
          },
          "spread": {
            "type": [
              "integer",
              "null"
            ]
          },
          "spread_pct": {
            "type": [
              "number",
              "null"
            ]
          },
          "voucher_competitive": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "nearby": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "zip": {
                  "type": "string"
                },
                "city": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CountyDetail": {
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "county": {
            "type": "string"
          },
          "county_slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "lastmod": {
            "type": "string",
            "format": "date"
          },
          "zip_count": {
            "type": "integer"
          },
          "zori_zip_count": {
            "type": "integer"
          },
          "medians": {
            "type": "object",
            "properties": {
              "fmr2": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "market_rent": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "fmr2_yoy_pct": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "zips": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndexZip"
            }
          }
        }
      },
      "SectionEight": {
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "fiscal_year": {
            "type": "integer",
            "example": 2026
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "lastmod": {
            "type": "string",
            "format": "date"
          },
          "summary": {
            "type": "object",
            "properties": {
              "n": {
                "type": "integer"
              },
              "voucher_competitive_count": {
                "type": "integer"
              },
              "median_spread_pct": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "zip": {
                  "type": "string"
                },
                "city": {
                  "type": "string"
                },
                "county": {
                  "type": "string"
                },
                "county_slug": {
                  "type": "string"
                },
                "fmr2": {
                  "type": "integer"
                },
                "market_rent": {
                  "type": "integer"
                },
                "spread": {
                  "type": "integer"
                },
                "spread_pct": {
                  "type": "number"
                },
                "voucher_competitive": {
                  "type": "boolean"
                },
                "url": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "MetaDoc": {
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "counts": {
            "type": "object",
            "properties": {
              "zips": {
                "type": "integer",
                "example": 914
              },
              "counties": {
                "type": "integer",
                "example": 87
              },
              "zips_with_market_rent": {
                "type": "integer",
                "example": 172
              },
              "section_8_rows": {
                "type": "integer",
                "example": 172
              }
            }
          },
          "vintages": {
            "type": "object"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}
