NMTC Low-Income Community Screener — IRA 48(e) Solar Bonus avatar

NMTC Low-Income Community Screener — IRA 48(e) Solar Bonus

Pricing

from $3.30 / 1,000 results

Go to Apify Store
NMTC Low-Income Community Screener — IRA 48(e) Solar Bonus

NMTC Low-Income Community Screener — IRA 48(e) Solar Bonus

Coordinate lookup for the IRA 48(e) low-income clean-energy bonus. Batch lat/lon against CDFI Fund NMTC Low-Income Communities (IRC 45D(e)); each returns in_nmtc_low_income_community, tract GEOID, poverty/MFI basis, Category 1 bonus flag, adder, and an optional HUD QCT flag. MCP-ready.

Pricing

from $3.30 / 1,000 results

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Share

CDFI NMTC Low-Income Community Screener - IRA 48(e) Bonus Credit

Batch-screen coordinates against the U.S. Treasury CDFI Fund map of New Markets Tax Credit low-income communities (IRC 45D(e)) - the Category 1 pathway to the Inflation Reduction Act's +10 percentage-point ITC adder under IRC 48(e) / 48E(h). One clean row per site, with the tract's poverty, income, unemployment and distress detail, the ACS vintage the answer came from, and two context flags: HUD LIHTC Qualified Census Tract, and federal Indian reservation (Category 2 context).

Keyless. Three services, queried live on every run:

SourceLayerLive count (2026-08-01)
CDFI Fund CIMS - NMTC LIC2016-2020 NMTC Qualified Census Tracts35,409
CDFI Fund CIMS - reservationsFederal Indian Reservation753
HUD - LIHTC QCT (context)QUALIFIED_CENSUS_TRACTS_202515,727

What changed in v1.1 (2026-08-01)

v1.1 is a hardening release. No output field was removed or renamed and the price is unchanged.

1. A failed lookup can no longer read as "not eligible"

v1.0 initialised in_nmtc_low_income_community and qualifies_48e_lowincome_bonus to false in the base row, so a malformed upstream body - an ArcGIS response with neither a features array nor an error, or an HTML page served with HTTP 200 - produced a billable row asserting the site was not a low-income community without ever having verified it. Every derived flag now starts null: null means not checked, false means checked and negative. Each row carries nmtc_status, qct_status and tribal_status; the NMTC layer is the only source that can decide Category 1, so eligibility stays null whenever it did not answer, no matter how healthy the context layers were. If the NMTC layer never answered for any asset, the run fails and bills nothing, and the billing gate runs before any row is pushed.

A source you deliberately switch off (checkQct: false, checkTribal: false) reports skipped_by_input and is not counted as a failure - v1.0 gave you null either way, so a switched-off lookup and a broken one were indistinguishable.

2. The layer is resolved by name, and the newest vintage wins

CIMS publishes three NMTC vintages side by side - layer 48 is 2006-2010, layer 47 is 2011-2015, layer 94 is 2016-2020. v1.0 hard-coded index 94 and a constant NMTC_VINTAGE string, which is one CDFI republish away from screening against a superseded map with a stale label on it. v1.1 reads the service's layer list, picks the newest <start>-<end> NMTC Qualified Census Tracts layer, verifies it still carries all 15 attributes the eligibility logic reads, and stamps nmtc_layer_id, nmtc_layer_name, nmtc_vintage, nmtc_vintage_start_year and nmtc_vintage_end_year on every row. If a newer layer appears without the expected attributes, the run fails rather than guessing.

3. lic_basis no longer presents a distress indicator as a statutory test

v1.0's lic_basis listed "Unemployment rate >=1.5x national average" alongside the poverty and income tests, as though it were one of the IRC 45D(e) low-income-community tests. It is not - it is a CDFI severe-distress indicator, and 13,196 of the 35,409 qualified tracts carry it. lic_basis now lists only the statutory tests the tract actually meets; the unemployment ratio and the high-out-migration rural flag moved to severe_distress_indicators, with the underlying values in unemployment_ratio_qualified, unemployment_rate_ratio and high_migration_rural_county.

4. Data that was fetched and thrown away is now emitted

v1.0 requested outFields=* on every query and emitted 8 attributes. UnemploymentRate, UnemploymentRateRatio, PovertyPopulation, NMTCQualified and all four Yes/No qualifier flags were retrieved on every single request and discarded. They now ship.

5. Live drift assertions run before any billable row

The CIMS layers store Web Mercator, so a dropped inSR=4326 makes the service answer HTTP 200 with zero features - a false clear. Measured live at South Bronx NY: 1 feature with inSR=4326, 0 without. Every run now proves: the NMTC layer resolves by name and carries its full attribute contract; the qualified-tract count sits in a measured band and excludes the 85,528-row all-tracts sibling layer; the count of rows with NMTCQualified <> 'Yes' is still 0, so layer membership really does prove low-income-community status; the Yes/No and Metro vocabularies contain no new codes; a positive canary (South Bronx must resolve to tract 36005007900); a second positive canary (Window Rock AZ must fall inside the Navajo Nation Reservation); and a negative control (an open-Pacific point must return exactly 0 from all three layers).

6. New: Category 2 (Indian land) context

on_federal_indian_reservation and federal_indian_reservation_name are informational context for the separate 48(e) Category 2 pathway. Statutory Indian land under 25 U.S.C. 3501(2) is broader than the federal-reservation layer, so false there does not rule Category 2 out - category_2_indian_land_note says so on every row.


Who this is for

  • Solar, storage and community-solar developers pre-screening a site pipeline for the 48(e) Category 1 low-income-community adder before committing to an application.
  • Tax equity investors and their counsel sanity-checking a sponsor's eligibility claim, with the tract detail and the ACS vintage on the record.
  • CDFIs and NMTC allocatees checking whether a project sits in a qualifying tract, and how distressed that tract actually is.
  • Site-selection and EPC teams layering the bonus onto the rest of the constraint picture.
  • AI agents doing site due diligence - see the MCP note below.

Example input

{
"assets": [
{ "lat": 40.815, "lon": -73.904, "label": "South Bronx, NY (low-income community, also a LIHTC QCT)" },
{ "lat": 35.6811, "lon": -109.0509, "label": "Window Rock, AZ (low-income community on the Navajo Nation)" },
{ "lat": 34.073, "lon": -118.4, "label": "Beverly Hills, CA (genuine clear - not a low-income community)" }
],
"checkQct": true,
"checkTribal": true,
"maxAssets": 500
}

That is the prefilled input. Live on build 1.1.x it returns three rows:

labelLIC48(e) Cat 1tractpovertyMFI %unemp ratioQCTreservation
South Bronx, NYtruetrue3600500790041.5%322.96xtrue-
Window Rock, AZtruetrue0400194500121.6%710.63xfalseNavajo Nation Reservation
Beverly Hills, CAfalsefalse----false-

Input fields

FieldTypeRequiredDescription
assetsarrayyesPoints to screen. Each item: lat, lon (WGS84 decimal degrees), optional label. One billable row per asset.
checkQctbooleannoDefault true. Also flag the HUD LIHTC Qualified Census Tract as context. Set false to skip; the row then reports qct_status: "skipped_by_input".
checkTribalbooleannoDefault true. Also flag a federal Indian reservation as IRC 48(e) Category 2 context. Set false to skip.
maxAssetsintegernoSafety cap on how many assets are screened. Default 500, max 5,000.

Omitting assets returns HTTP 400 at run creation - the run never starts and nothing is billed.


Output fields

One row per screened asset. Every one of the 54 declared fields is listed here.

null on a flag always means the backing source did not answer, never the answer is no.

FieldTypeDescription
asset_labelstringnull
asset_latnumbernull
asset_lonnumbernull
in_nmtc_low_income_communitybooleannull
tract_geoidstringnull
statestringnull
countystringnull
county_fipsstringnull
metro_designationstringnull
poverty_ratenumbernull
pct_median_family_incomenumbernull
lic_basisstringnull
qualifies_48e_lowincome_bonusbooleannull
bonus_categorystringnull
adderstringnull
also_in_lihtc_qctbooleannull
nmtc_vintagestringnull
citationstringnull
errorstringnull
source_urlstringnull
checked_atstringnull
nmtc_statusstringnull
nmtc_errorstringnull
qct_statusstringnull
qct_errorstringnull
tribal_statusstringnull
tribal_errorstringnull
sources_ok_countintegernull
sources_total_countintegernull
partial_resultbooleannull
nmtc_layer_idintegernull
nmtc_layer_namestringnull
nmtc_vintage_start_yearintegernull
nmtc_vintage_end_yearintegernull
metro_designation_normalizedstringnull
unemployment_ratenumbernull
unemployment_rate_rationumbernull
poverty_populationintegernull
poverty_rate_qualifiedbooleannull
median_income_qualifiedbooleannull
unemployment_ratio_qualifiedbooleannull
high_migration_rural_countybooleannull
cdfi_nmtc_qualified_flagbooleannull
lic_qualifying_testsarraynull
severe_distress_indicatorsstringnull
on_federal_indian_reservationbooleannull
federal_indian_reservation_namestringnull
federal_indian_reservation_geoidstringnull
category_2_indian_land_notestringnull
bonus_eligibility_basisstringnull
disclaimerstringnull
source_url_qctstringnull
source_url_tribalstringnull
actor_versionstringnull

Fields that are legitimately null on a healthy run

A dead-column audit over the FULL dataset of a live run with the schema prefill leaves exactly four fields null: nmtc_error, qct_error, tribal_error and error. All four being null is good news - it means every source answered. Each is pinned by a fault-injection fixture in offline.test.js and populates on any run during an upstream outage.

The tract-detail fields are null on a clear (there is no containing tract to describe), and federal_indian_reservation_* is null off-reservation; the prefill deliberately includes a reservation hit and a clear so every column populates on an auto-QA run.


Use as an MCP tool

This Actor is available to AI agents through mcp.apify.com. It takes plain coordinates and returns a flat, self-describing row: qualifies_48e_lowincome_bonus for the yes/no, bonus_eligibility_basis for why, nmtc_vintage for the data vintage, and nmtc_status / qct_status / tribal_status so an agent can tell a verified negative from an unanswered one.

Pricing

$6 per 1,000 results (pay-per-event, one Result event per screened asset). Graduated discounts apply on paid Apify plans. There are no other charge events.

Billing honesty: if the NMTC layer does not answer for a single asset, the run fails and emits nothing, so you are not billed for an outage.

FAQ

Does a hit mean I get the +10 point adder? No. The 48(e) Low-Income Communities Bonus Credit is capacity-limited and allocated by application through the DOE program. Sitting in a qualifying tract is a necessary condition, not an allocation.

Is this the "energy community" bonus? No, and this is the most common confusion. The IRA has two different +10 point adders. This Actor screens the low-income community bonus (IRC 48(e)/48E(h), Category 1, defined by cross-reference to the NMTC low-income community in IRC 45D(e)). The separate energy community bonus (IRC 45(b)(11) / 48(a)(14)) covers brownfield sites, statistical areas with historical fossil-fuel employment, and census tracts with a retired coal mine or coal-fired plant - that is not checked here.

What about Categories 2, 3 and 4? Category 2 is Indian land, Category 3 a qualified low-income residential building project, Category 4 a qualified low-income economic benefit project. None of them is decided here. on_federal_indian_reservation is informational Category 2 context only, and statutory Indian land under 25 U.S.C. 3501(2) is broader than the federal-reservation layer, so false there does not rule Category 2 out.

Why does a tract show unemployment_ratio_qualified: true but that reason is missing from lic_basis? Because the unemployment ratio is a CDFI severe-distress indicator, not one of the IRC 45D(e) low-income-community tests. It is reported in severe_distress_indicators. v1.0 listed it inside lic_basis, which overstated the statutory basis.

A tract is qualified but lic_qualifying_tests is empty - why? 168 of the 35,409 qualified tracts carry neither the poverty nor the income flag; the CDFI Fund qualified them by another route, such as the IRC 45D(e)(2) high-out-migration rural special rule. lic_basis falls back to the generic designation statement and cdfi_nmtc_qualified_flag still reads true.

Why did my run fail with "LIVE DRIFT CHECK FAILED"? Because CDFI Fund CIMS no longer matches what this Actor was verified against - a renamed or re-vintaged layer, a new vocabulary code, a qualified-tract layer that no longer contains only qualified tracts, or a canary that stopped returning known-good data. A loud failure is the correct answer there. Nothing is billed on a failed run.

Is this tax advice? No. It is an informational screen against public CDFI Fund and HUD data. Confirm against CDFI Fund CIMS, the DOE program rules and IRS guidance with tax counsel.

  • HUD QCT + DDA Screener - the LIHTC 130% basis boost for the same coordinate.
  • HUD Affordable Housing Explorer - LIHTC, multifamily and public-housing inventory plus Opportunity Zones.
  • Tribal Land Jurisdiction Screener - a fuller jurisdictional picture than the reservation context flag here.
  • Site Due Diligence Bundle - 20 federal constraint layers for one coordinate.

Informational screening tool built on public U.S. Treasury CDFI Fund and HUD data. Not tax advice, and not an IRS or CDFI Fund determination. The 48(e) adder is capacity-limited and allocated by application. Confirm with the CDFI Fund, the DOE program and your tax counsel before relying on it.