When a rental property is damaged by fire, flood, or a major system failure, two insurance questions must be answered quickly: what did the owner lose in rental income during the repair period, and was the rental income coverage set at the right level to begin with? Both questions require the same underlying data - a defensible estimate of market rent for the specific property at the time of loss. Getting this right matters because loss-of-rent claims on multifamily properties routinely run $15,000 to $80,000, and the market rent figure anchors the entire calculation.

This post covers both the claims-side workflow (loss-of-rent ACV calculation) and the underwriting-side workflow (coverage adequacy review), and shows exactly how to build both using the RentComp API alongside HUD Fair Market Rent data. For context on DSCR lending workflows that use similar data, see our post on DSCR loan underwriting with rental income APIs. For HUD FMR integration specifics, see HUD Fair Market Rent API integration.

The Two Insurance Use Cases

1. Loss-of-Rent Claims (Actual Cash Value of Lost Income)

Loss-of-rent coverage (also called "fair rental value" coverage) pays the property owner for rental income they cannot collect while the property is uninhabitable. The claim calculation is straightforward in theory: market rent per month times the number of months the property is uninhabitable. In practice, disputes arise when the adjuster and the claimant disagree on what "market rent" was at the time of loss.

The adjuster's default approach - pull up Zillow or Rentometer and eyeball a number - creates several problems. The data is stale (Zillow rental estimates often lag the market by 6-12 months). It is not address-specific (Zillow estimates for a ZIP code, not for a specific unit at a specific address with specific specs). And it produces no audit trail - the adjuster cannot explain exactly which comparable listings informed the number if the claim is disputed.

2. Coverage Adequacy Review at Renewal

At policy renewal, underwriters should verify that the declared rental income on the policy schedule matches current market rates. If a landlord declared $1,400/month when they wrote the policy three years ago and market rent has risen to $1,750/month, the policy is underinsured. In a total loss scenario, the insurer pays out on $1,400/month when the actual economic loss is $1,750/month - and the policyholder has a legitimate grievance.

For a carrier with 50,000 rental properties in their portfolio, manual verification is impossible. Automated batch processing using a rental comp API makes annual coverage adequacy reviews feasible at scale.

Why Current Methods Fail

The standard adjuster workflow is: open Zillow, type in the address, screenshot the "Zestimate" rent estimate, attach it to the claim file. This approach fails in four specific ways:

The Four-Data-Point Standard for Defensible Estimates

For a rental income estimate to hold up in a claim dispute or regulatory audit, it should document four data points:

  1. Median comparable rent - the market_stats.median from the comp query, reflecting current-listed comparable units
  2. Low comparable rent - the market_stats.p25 (25th percentile), representing the low end of the market for comparable units
  3. High comparable rent - the market_stats.p75 (75th percentile), the high end
  4. HUD Fair Market Rent - the FMR for the property's ZIP code and bedroom count, which serves as a regulatory floor anchored to federal methodology

Together, these four numbers tell the full story: here is where the market sits, here is the range, and here is the HUD floor that confirms the estimate is not outlier-driven. When a claim is disputed, this documentation answers every question a mediator or judge will ask.

Python Code: The Insurance Rental Income Report

import requests
import json
from datetime import datetime

RENTCOMP_API_KEY = "your_api_key"
RENTCOMP_BASE = "https://api.rentcompapi.com/v1"


def generate_insurance_rental_report(
    address: str,
    bedrooms: int,
    bathrooms: float,
    sqft: int,
    loss_date: str,
    repair_months: float,
    policy_declared_rent: float
) -> dict:
    """
    Generate a defensible rental income estimate for insurance purposes.

    Returns a structured report with comp data, FMR, and claim calculations.
    """
    report = {
        "generated_at": datetime.utcnow().isoformat() + "Z",
        "address": address,
        "unit_specs": {
            "bedrooms": bedrooms,
            "bathrooms": bathrooms,
            "sqft": sqft,
        },
        "loss_date": loss_date,
        "repair_months": repair_months,
        "policy_declared_rent": policy_declared_rent,
    }

    # Step 1: Pull rental comps
    comp_resp = requests.post(
        f"{RENTCOMP_BASE}/comps",
        headers={"Authorization": f"Bearer {RENTCOMP_API_KEY}"},
        json={
            "address": address,
            "bedrooms": bedrooms,
            "bathrooms": bathrooms,
            "sqft": sqft,
            "radius_miles": 1.0,
            "max_age_days": 90,
        },
        timeout=20
    )

    if not comp_resp.ok:
        report["error"] = f"Comp API error: {comp_resp.status_code}"
        return report

    comp_data = comp_resp.json()
    stats = comp_data.get("market_stats", {})
    comps = comp_data.get("comps", [])

    report["comp_data"] = {
        "comp_count": comp_data.get("comp_count", 0),
        "confidence_score": comp_data.get("confidence_score", 0),
        "market_stats": stats,
        "comp_table": [
            {
                "address": c.get("address"),
                "bedrooms": c.get("bedrooms"),
                "sqft": c.get("sqft"),
                "monthly_rent": c.get("monthly_rent"),
                "listed_date": c.get("listed_date"),
                "distance_miles": round(c.get("distance_miles", 0), 2),
            }
            for c in comps[:10]  # Include up to 10 comps in the report
        ],
    }

    # Step 2: Pull HUD Fair Market Rent
    fmr_resp = requests.get(
        f"{RENTCOMP_BASE}/fair-market-rent",
        headers={"Authorization": f"Bearer {RENTCOMP_API_KEY}"},
        params={"address": address, "bedrooms": bedrooms},
        timeout=15
    )

    if fmr_resp.ok:
        fmr_data = fmr_resp.json()
        report["hud_fmr"] = {
            "fmr_amount": fmr_data.get("fmr"),
            "fiscal_year": fmr_data.get("fiscal_year"),
            "metro_area": fmr_data.get("metro_area"),
            "source": "HUD 40th Percentile Fair Market Rent",
        }
        fmr_amount = fmr_data.get("fmr", 0)
    else:
        report["hud_fmr"] = {"error": "FMR data unavailable"}
        fmr_amount = 0

    # Step 3: Calculate defensible market rent
    market_median = stats.get("median", 0)
    confidence = comp_data.get("confidence_score", 0)

    # Use higher of market median or FMR (FMR is the floor)
    defensible_market_rent = max(market_median, fmr_amount)

    # Flag low-confidence results
    if confidence < 60:
        report["flag"] = "LOW_CONFIDENCE - human review required"

    # Step 4: Calculate claim amounts
    lost_rent_claim = defensible_market_rent * repair_months
    policy_gap = defensible_market_rent - policy_declared_rent
    policy_gap_pct = (policy_gap / policy_declared_rent * 100
                      if policy_declared_rent else 0)

    report["rental_income_estimate"] = {
        "defensible_market_rent": round(defensible_market_rent, 2),
        "market_median_comp_rent": round(market_median, 2),
        "hud_fmr": round(fmr_amount, 2),
        "low_comp_rent": round(stats.get("p25", 0), 2),
        "high_comp_rent": round(stats.get("p75", 0), 2),
        "basis": "Market median" if market_median >= fmr_amount else "HUD FMR floor",
    }

    report["claim_calculation"] = {
        "monthly_loss": round(defensible_market_rent, 2),
        "repair_months": repair_months,
        "total_loss_of_rent_claim": round(lost_rent_claim, 2),
    }

    report["coverage_adequacy"] = {
        "policy_declared_rent": policy_declared_rent,
        "current_market_rent": round(defensible_market_rent, 2),
        "gap_dollars": round(policy_gap, 2),
        "gap_pct": round(policy_gap_pct, 1),
        "status": (
            "ADEQUATE" if abs(policy_gap_pct) <= 10
            else "UNDERINSURED" if policy_gap > 0
            else "OVERINSURED"
        ),
    }

    return report


# Example: fire claim at a duplex in Nashville
report = generate_insurance_rental_report(
    address="4521 Murphy Rd, Nashville, TN 37209",
    bedrooms=2,
    bathrooms=1.0,
    sqft=950,
    loss_date="2026-02-15",
    repair_months=4.5,
    policy_declared_rent=1350.00
)

print(json.dumps(report, indent=2))

Using Confidence Score in the Claims Workflow

The confidence score is a quality gate in a claims workflow, not a nice-to-have. The rule should be explicit:

Low-confidence results are concentrated in rural markets (thin listing density) and very niche unit types. A 5BR house in rural Wyoming may have zero comparable listings within 10 miles - in that case, HUD FMR is genuinely the most defensible number you have, and that is fine to say explicitly in the claim documentation.

Batch Processing for Portfolio Reviews

For carriers running annual coverage adequacy reviews, the batch approach is straightforward. Export the policy schedule (address, declared rent, beds/baths/sqft, policy number) and run it through a batch job that fires POST /comps and GET /fair-market-rent for each property. Flag any property where the declared rent differs from current market by more than 15% - those are the policies that need premium adjustment at renewal.

At typical API response times of 200-400ms per call and a 10-concurrent-request limit, a 10,000-property portfolio processes in roughly 20-40 minutes using Python's asyncio + aiohttp. That is a full portfolio review running overnight as a scheduled job.

Integration with Claims Management Systems

For carriers using Guidewire ClaimCenter or Duck Creek Claims, the rental income report integrates cleanly via REST webhook. The workflow:

  1. Claim created in ClaimCenter for a rental property
  2. ClaimCenter fires a webhook to your middleware service with claim ID, property address, and unit specs
  3. Middleware calls the RentComp API, generates the structured report
  4. Middleware posts the report back to ClaimCenter via the Guidewire REST API, attaching it to the claim as a document with structured data fields
  5. Adjuster opens the claim and sees the pre-populated market rent estimate with full comp table

This eliminates the manual Zillow step entirely. The adjuster still applies judgment - they can override the estimate if they have specific local knowledge - but they start from a documented, defensible baseline rather than a screenshot.

Regulatory Considerations by State

Documentation requirements for ACV calculations vary by state and are worth knowing before building automated workflows. California requires that market data used in claims calculations be current (within 90 days of loss) - the RentComp API's default 90-day listing window satisfies this. Texas DOI guidelines suggest that rental income estimates should be based on comparable properties within the same submarket, which aligns directly with the radius and similarity filtering the API applies. New York's Department of Financial Services requires that loss-of-rent disputes involving amounts over $50,000 include a licensed appraiser's opinion - the API report is useful documentation for the appraiser but does not replace their sign-off in these cases.

The safest practice is to include the full comp table (not just the median) and the HUD FMR reference in every claim file. This demonstrates methodology transparency and gives any reviewing party the ability to assess the quality of the underlying data.

Ready to Pull Rental Comps via API?

Join the waitlist and get 80% off founding member pricing - for life.

Join the Waitlist