HUD Section 8 Contract Expiration Monitor + Owner Contacts
Pricing
from $6.60 / 1,000 contract rows
HUD Section 8 Contract Expiration Monitor + Owner Contacts
Every HUD project-based Section 8, 202 and 811 HAP contract with its true term end (not the funding increment), assisted units, rent-vs-FMR position, owner and management-agent contacts, and a new-since-last-run delta.
Pricing
from $6.60 / 1,000 contract rows
Rating
0.0
(0)
Developer
Kyle Maloney
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Every HUD project-based Section 8, 202 and 811 HAP contract in the United States, with the date the contract term actually ends, assisted units, rent-vs-FMR position, owner and management-agent contacts, and a new-since-last-run delta.
Sourced live on every run from HUD's two published Multifamily files — 24,315 contracts covering 1,483,851 assisted units across 23,612 properties (measured 2026-08-17 on the 2026-08-11 vintage).
Who it is for
- Affordable-housing acquirers and preservation developers — find the contracts that genuinely come up for renewal in your window, with the owner's name, mailing address, phone and email already on the row.
- LIHTC syndicators and Year-15 buyers — screen Section 202/811 and older Section 8 stock by term end, rent position and Opportunity Zone status.
- Lenders and mortgage bankers — size the HAP-expiry exposure in a market before underwriting.
- Housing policy researchers and state housing agencies — build an honest expiring- contract pipeline instead of one inflated roughly four-fold.
The thing this actor exists to get right
HUD publishes two expiration dates and the obvious one is not the contract term end.
| HUD column | What it actually is | 24-month screen (from 2026-08-18) |
|---|---|---|
tracs_overall_expiration_date | Contract term end — the genuine renewal / opt-out decision point | 4,627 contracts / 126,711 units |
tracs_current_expiration_date | End of the current funding increment — routine annual funding | 18,939 contracts / 1,184,903 units |
That is 4.09x the contracts and 9.35x the assisted units for the same window. The
evidence that the overall column is the term end: tracs_effective_date plus
contract_term_months_qty lands on it for 22,580 of 24,315 contracts (92.9%) and on
the current column for only 8,483 (34.9%).
The clearest single case is Starrett City in Brooklyn, the largest project-based Section 8 contract in the country at 3,569 assisted units. Its current funding increment ends 2027-01-31. Its contract term runs to 2041-01-31. Screening on the increment column tells an acquirer that a 3,569-unit HAP contract expires in five months when it has fifteen years left.
This actor defaults to expirationBasis: "overall" and ships both dates on every
row, labelled — contract_term_end_date and current_funding_increment_end_date —
along with expiration_dates_differ, expiration_gap_days and
term_end_reconciles_with_effective_plus_term so you can see the reasoning rather than
trust it. Set expirationBasis: "current" if you specifically want the funding-increment
calendar; nothing is hidden from you either way.
Example input
{"states": ["CA"],"expirationBasis": "overall","expiringWithinMonths": 36,"contractStatuses": ["Active"],"maxResults": 300}
Other useful shapes:
{ "contractNumbers": ["NY36M000277"] }{ "states": ["TX", "OK"], "expiringFiscalYears": ["2027", "2028"], "minAssistedUnits": 50 }{ "ownerSearch": "Fairstead", "expirationBasis": "either", "expiringWithinMonths": 60 }{ "states": ["OH"], "deltaOnly": true }
What it will refuse to do
This actor never returns a green empty run in place of an answer it could not compute.
- No scope (
{}) — fails immediately rather than dumping and billing all 24,315 contracts. - An unparseable filter — a three-letter state code, a non-numeric property id, an
unknown
expirationBasis— fails and names the field. It is never silently dropped. - Either HUD file unreachable or unparseable — fails. The properties file is where state, county, MSA, owner and management-agent contacts come from, so a run without it would publish nulls that read as verified absences.
- HUD's data no longer matching the contract this actor was tested against — fails, with the specific measurement that moved.
Every failure message ends "Nothing was emitted and nothing was billed."
A query that is well-formed, reaches HUD, and genuinely matches nothing returns 0 rows and SUCCEEDS. That is the answer.
The live drift gate
Before a single row is buffered — and long before anything is pushed or billed — every run re-measures HUD's files against the properties this actor was built on. All of these are logged on every run, so a future tightening can be evidence-based:
| Check | Live value 2026-08-17 | Fails at |
|---|---|---|
| Contract row count | 24,315 | below 20,000 |
| Property row count | 23,612 | below 20,000 |
| Contract-to-property join coverage | 100.00% | below 95% |
| HUD's published fiscal year vs the one derived from the term-end date | 100.00% | below 99% |
| Term end later than funding-increment end | 63.18% | below 20% |
| Positive canary NY36M000277 (Starrett City) | 3,569 units, NY, term 2041-01-31 > increment 2027-01-31 | any mismatch |
| Negative control ZZ00X000000 | 0 matches | any match |
| Unrecognised status / doc type / program group | 0.00% | above 5% |
| File vintage age | 6 days | above 400 days |
The fifth row is the product premise: if HUD ever collapses the two expiration columns into one meaning, "contract term end" stops being separable from "current funding increment end" and this actor fails loudly rather than publishing the wrong pipeline.
New-since-last-run delta
deltaOnly: true returns only contracts that are new, or whose term end, funding
increment end, assisted units or status moved since the previous run.
Two things this deliberately does not do:
- The baseline lives in a named key-value store, not the per-run default store. A per-run store would make every contract read "new" on every run, forever, and bill the full file as a delta.
- The baseline is always the full national universe, never the filtered subset. A California-scoped run cannot make the next Texas-scoped run report everything as new.
On the very first run there is no baseline, so is_new_since_last_run is null, not
true — "we have never seen this file" is not the same claim as "this contract is new".
delta_status reads baseline_established.
Data quality decisions you can audit
Every one of these was measured on the live file, and each is visible on the row rather than resolved silently.
rent_to_FMR_ratio = 0is a null sentinel, carried by exactly the 334 contracts whoserent_to_FMR_descriptionreads "Unknown". Reading those zeros as real would rank them as the deepest below-FMR contracts in America — the most attractive preservation targets — off data HUD never published.rent_to_fmr_pctisnullthere andrent_to_fmr_basissayszero_sentinel_not_published.msa_code = "9999"is an undocumented second sentinel on 6,489 of 23,612 properties (27.5%), with a null MSA name, carried by properties plainly inside metro areas including Starrett City in Brooklyn."0000"is HUD's documented "Not In Metro Area" (681 properties). Both are suppressed frommsa_codeand preserved inmsa_code_rawwithmsa_sentinel_meaning.- State comes from the property record, never the contract number. The first two
characters of a contract number look like a state code but disagree with the property's
own
state_codeon 229 of 24,315 contracts (0.94%) — the territories use a separate vocabulary (RQ for PR ×196, VQ for VI ×19, TQ for MP ×4, GQ for GU ×1) and nine contracts are genuinely cross-border (OR→WA ×6, MD→DC, LA→MS, RQ→VI). Both values ship, withstate_prefix_matches_property_state. - A bedroom-size FMR of 0 alongside a non-zero unit count of that size is missing, not $0 (680 contracts).
- A participant id of 0 is a null sentinel, not participant zero (37 owner rows, 82 agent rows).
- HUD uses three different blank conventions in one pair of files — whitespace
padding on the property block, a single space on the owner/agent block, an empty string
on
associated_financing_Numberandownership_effective_date. All becomenull. - The properties sheet ends with three entirely blank rows inside its declared range. They are dropped rather than emitted as three all-null properties.
- Four contracts publish a funding increment ending after the contract term, and one
publishes no current expiration at all. Flagged via
expiration_dates_inconsistent, never normalised away. - 70 properties have contract assisted units exceeding HUD's own total unit count.
Flagged via
assisted_units_exceed_property_total, never clamped. - The data vintage is read from the
Last-Modifiedheader on every run and published on every row. HUD replaces these files in place, so the vintage cannot be inferred from the URL.
Use as an MCP tool
This actor is callable by AI agents over Apify's hosted MCP endpoint. Add it to a client config:
{"mcpServers": {"apify": {"command": "npx","args": ["-y", "@apify/actors-mcp-server", "--actors", "malonestar/hud-section8-contract-expiration-monitor"],"env": { "APIFY_TOKEN": "your-apify-token" }}}}
A worked agent prompt: "List every HUD Section 8 contract in Ohio whose contract term ends in federal fiscal year 2028, with at least 100 assisted units, and give me the owner's email and phone for each."
Billing is unchanged when called as a tool: one dataset row is one billable result, and a run that cannot answer fails without billing.
Related actors
hud-affordable-housing-explorer— LIHTC, multifamily and public-housing inventory with Opportunity Zone overlay.hud-qct-lihtc-boost-screener— Qualified Census Tract and 130% basis-boost eligibility.fema-nri-county-risk-profile— county and tract natural-hazard risk for the same assets.
Output fields
All 148 fields are documented here and declared in the dataset schema.
Every field is nullable unless it is structurally always present. null means not
checked; false means checked and negative. The two are never collapsed.
| Field | Type | Description |
|---|---|---|
contract_number | string | null |
property_id | integer | null |
property_name | string | null |
contract_status | string | null |
contract_status_is_active | boolean | null |
contract_status_vocabulary_known | boolean | null |
contract_doc_type_code | string | null |
program_type_name | string | null |
program_type_group_code | string | null |
program_type_group_name | string | null |
is_hud_administered | boolean | null |
is_old_acc | boolean | null |
is_performance_based_acc | boolean | null |
assisted_units | integer | null |
units_0br | integer | null |
units_1br | integer | null |
units_2br | integer | null |
units_3br | integer | null |
units_4br | integer | null |
units_5plus_br | integer | null |
bedroom_counts_reconcile_with_assisted_units | boolean | null |
expiration_basis_used | string | null |
expiration_date_used | string | null |
months_to_expiration_used | integer | null |
contract_effective_date | string | null |
contract_term_months | integer | null |
contract_term_end_date | string | null |
contract_term_end_fiscal_year | integer | null |
contract_term_end_fiscal_quarter | string | null |
contract_term_end_fiscal_year_derived | integer | null |
current_funding_increment_end_date | string | null |
current_increment_end_fiscal_year | integer | null |
current_increment_end_fiscal_quarter | string | null |
tracs_overall_expiration_serial_raw | integer | null |
tracs_current_expiration_serial_raw | integer | null |
expiration_dates_differ | boolean | null |
expiration_gap_days | integer | null |
expiration_dates_inconsistent | boolean | null |
term_end_reconciles_with_effective_plus_term | boolean | null |
days_to_term_end | integer | null |
days_to_current_increment_end | integer | null |
term_end_is_past | boolean | null |
current_increment_end_is_past | boolean | null |
rent_to_fmr_pct | number | null |
rent_to_fmr_band | string | null |
rent_to_fmr_basis | string | null |
rent_above_fmr | boolean | null |
rent_at_or_below_80pct_fmr | boolean | null |
fmr_0br | integer | null |
fmr_1br | integer | null |
fmr_2br | integer | null |
fmr_3br | integer | null |
fmr_4br | integer | null |
property_join_status | string | null |
hub_name | string | null |
servicing_site_name | string | null |
property_address_line1 | string | null |
property_address_line2 | string | null |
property_city | string | null |
property_state_code | string | null |
property_zip_code | string | null |
property_zip4_code | string | null |
state_from_contract_number_prefix | string | null |
state_prefix_matches_property_state | boolean | null |
county_code | string | null |
county_name | string | null |
msa_code | string | null |
msa_code_raw | string | null |
msa_name | string | null |
msa_code_is_sentinel | boolean | null |
msa_sentinel_meaning | string | null |
congressional_district_code | string | null |
placed_base_city_name | string | null |
property_phone | string | null |
property_phone_digits | string | null |
property_total_units | integer | null |
assisted_unit_share_pct | number | null |
assisted_units_exceed_property_total | boolean | null |
property_category | string | null |
primary_financing_type | string | null |
associated_financing_number | string | null |
ownership_effective_date | string | null |
is_insured | boolean | null |
is_202_or_811 | boolean | null |
is_hud_held | boolean | null |
is_hud_owned | boolean | null |
is_hospital | boolean | null |
is_nursing_home | boolean | null |
is_board_and_care | boolean | null |
is_assisted_living | boolean | null |
is_refinanced | boolean | null |
is_section_221d3 | boolean | null |
is_section_221d4 | boolean | null |
is_section_236 | boolean | null |
is_non_insured | boolean | null |
is_bmir | boolean | null |
is_risk_sharing | boolean | null |
is_mip | boolean | null |
is_co_insured | boolean | null |
is_opportunity_zone | boolean | null |
owner_contact_status | string | null |
owner_participant_id | integer | null |
owner_company_type | string | null |
owner_organization_name | string | null |
owner_individual_full_name | string | null |
owner_individual_title | string | null |
owner_address_line1 | string | null |
owner_address_line2 | string | null |
owner_city | string | null |
owner_state_code | string | null |
owner_zip_code | string | null |
owner_zip4_code | string | null |
owner_phone | string | null |
owner_phone_digits | string | null |
owner_fax | string | null |
owner_email | string | null |
mgmt_agent_contact_status | string | null |
mgmt_agent_participant_id | integer | null |
mgmt_agent_company_type | string | null |
mgmt_agent_org_name | string | null |
mgmt_agent_individual_full_name | string | null |
mgmt_agent_individual_title | string | null |
mgmt_agent_address_line1 | string | null |
mgmt_agent_address_line2 | string | null |
mgmt_agent_city | string | null |
mgmt_agent_state_code | string | null |
mgmt_agent_zip_code | string | null |
mgmt_agent_zip4_code | string | null |
mgmt_agent_phone | string | null |
mgmt_agent_phone_digits | string | null |
mgmt_agent_fax | string | null |
mgmt_agent_email | string | null |
owner_is_own_management_agent | boolean | null |
delta_status | string | null |
is_new_since_last_run | boolean | null |
delta_changed_fields | array | null |
delta_previous_values | object | null |
baseline_built_at | string | null |
baseline_contract_count | integer | null |
contracts_data_vintage | string | null |
properties_data_vintage | string | null |
contracts_source_status | string | null |
properties_source_status | string | null |
retrieved_at | string | null |
matched_rows_total | integer | null |
results_truncated | boolean | null |
max_results_applied | integer | null |
expiration_basis_requested | string | null |
Source
https://www.hud.gov/sites/dfiles/Housing/documents/MF-Assistance-Sec8-Contracts1.xlsx(24,315 contracts x 31 columns)https://www.hud.gov/sites/dfiles/Housing/documents/MF-Properties-with-Assistance-Sec8-Contracts1.xlsx(23,612 properties x 74 columns)
Both are public, keyless, and joined on property_id. Vintage 2026-08-11 as measured
2026-08-17; HUD republishes roughly monthly and replaces the files in place.
FAQ
When does a HUD Section 8 contract actually expire? On its contract term end
(contract_term_end_date). The current funding increment end is a routine annual
funding action, not the renewal decision.
Can I get the owner's email and phone? Yes. Owner email is populated on 23,459 of
23,612 properties (99.35%) and the management agent email on 23,426 (99.21%), across
11,151 and 10,374 distinct addresses respectively. Owner mailing address, phone and
company type ship too, plus owner_contact_status so a partial record is visible.
How do I find expiring Section 8 contracts in my state?
{"states":["CA"], "expiringWithinMonths":36,"contractStatuses":["Active"]}How do I monitor for new or amended contracts? Schedule the actor and set
deltaOnly: true. The first run establishes a full-universe baseline and reports
baseline_established; subsequent runs report only what moved.
Which contracts have rents below FMR? Filter on rent_at_or_below_80pct_fmr or
sort by rent_to_fmr_pct. Rows where HUD published no rent position carry null, not
0, so they cannot masquerade as deep discounts.
Does this cover Section 202 and 811? Yes: 5,687 PRAC 202/811 contracts, 3,894 Section 202, 953 811 PRA Demo and 121 PAC 202/811, alongside the Section 8 stock.