{"openapi":"3.1.0","info":{"title":"EquityUp API","version":"1.0.0"},"paths":{"/api/v1/hpa-rules":{"get":{"tags":["public-api"],"summary":"PMI cancellation thresholds under the Homeowners Protection Act","description":"Returns every loan-to-value threshold at which private mortgage insurance can be cancelled or must terminate under the federal Homeowners Protection Act, each with its United States Code citation, plus the FHA mortgage insurance premium vintage rules. Static data; no inputs required.","operationId":"hpa_rules_api_v1_hpa_rules_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HpaRulesResponse"}}}}}}},"/api/v1/pmi-eligibility":{"post":{"tags":["public-api"],"summary":"Evaluate a mortgage against the HPA PMI cancellation thresholds","description":"Computes loan-to-value and evaluates it against every applicable threshold in the federal Homeowners Protection Act, returning the statutory citation for each. Takes no address and no identifying information, stores nothing, and is not property-specific — supply the property value yourself. Educational; not a lending decision.","operationId":"pmi_eligibility_api_v1_pmi_eligibility_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PmiEligibilityRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PmiEligibilityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/market/{zip_code}":{"get":{"tags":["public-api"],"summary":"City-level home value aggregate for a covered Utah ZIP code","description":"Returns the average assessed market value, average building square footage, and valued parcel count for detached single-family homes in one ZIP code, derived from public county assessor parcel records, together with the source, the filter applied, and the computation date. Covers Utah, Salt Lake, Davis, and Weber counties.","operationId":"market_data_api_v1_market__zip_code__get","parameters":[{"name":"zip_code","in":"path","required":true,"schema":{"type":"string","title":"Zip Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataResponse"}}}},"404":{"description":"ZIP code outside the covered service area."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HpaPathway":{"properties":{"basis":{"type":"string","title":"Basis","description":"Which value the threshold is applied to."},"threshold_ltv":{"type":"number","title":"Threshold Ltv","description":"LTV at or below which this path opens, as a decimal."},"citation":{"type":"string","title":"Citation","description":"United States Code citation for this threshold."},"ltv":{"type":"number","title":"Ltv","description":"The loan-to-value ratio on this basis, as a decimal."},"meets_threshold":{"type":"boolean","title":"Meets Threshold","description":"Whether the LTV is at or below the threshold."},"paydown_needed_usd":{"type":"integer","title":"Paydown Needed Usd","description":"Principal reduction still needed to reach the threshold, holding the property value fixed. Zero when the threshold is already met."},"appreciation_needed_usd":{"type":"integer","title":"Appreciation Needed Usd","description":"Increase in property value still needed to reach the threshold, holding the loan balance fixed. This is a LARGER figure than paydown_needed_usd, not an alternative name for it: reaching a 75% threshold on a $400,000 balance takes $40,000 of paydown against a $480,000 value, but $53,333 of appreciation. Zero when the threshold is already met."}},"type":"object","required":["basis","threshold_ltv","citation","ltv","meets_threshold","paydown_needed_usd","appreciation_needed_usd"],"title":"HpaPathway","description":"One statutory route to cancellation, evaluated against the inputs."},"HpaRulesResponse":{"properties":{"api_version":{"type":"string","title":"Api Version"},"retrieved_at":{"type":"string","title":"Retrieved At","description":"UTC timestamp this response was produced, ISO 8601."},"source":{"type":"string","title":"Source"},"documentation":{"type":"string","title":"Documentation","description":"Human-readable documentation for this API."},"statute":{"type":"string","title":"Statute","description":"The governing statute."},"jurisdiction":{"type":"string","title":"Jurisdiction"},"rules":{"type":"object","title":"Rules","description":"Thresholds and citations, as `hpa.originalValue.borrowerRequested`, `hpa.originalValue.automaticTermination`, `hpa.currentValue.underSplit`, `hpa.currentValue.atOrOverSplit` — each an object with `threshold` (a decimal LTV) and `citation` (a United States Code reference) — plus `hpa.effectiveDate`, `hpa.loanAgeSplitYears`, and the `fha` vintage rules."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes"},"disclaimer":{"type":"string","title":"Disclaimer"},"limitations":{"items":{"type":"string"},"type":"array","title":"Limitations"}},"type":"object","required":["api_version","retrieved_at","source","documentation","statute","jurisdiction","rules","notes","disclaimer","limitations"],"title":"HpaRulesResponse","description":"The PMI cancellation thresholds, with their statutory citations.\n\n`rules` is the serialized form of utils.calculator.calculator_config() and\nis typed as a free-form object on purpose: it is the single source of truth\nfor the thresholds, and mirroring its shape into a Pydantic model here\nwould be the second copy this whole design exists to avoid. Its structure\nis documented at /for-ai-agents."},"MarketDataResponse":{"properties":{"zip_code":{"type":"string","title":"Zip Code"},"city":{"type":"string","title":"City"},"county":{"type":"string","title":"County"},"avg_value_usd":{"type":"integer","title":"Avg Value Usd","description":"Average assessed market value of a single-family home."},"avg_sqft":{"type":"integer","title":"Avg Sqft","description":"Average building square footage."},"price_per_sqft_usd":{"type":"integer","title":"Price Per Sqft Usd","description":"Average assessed value per building square foot."},"parcel_count":{"type":"integer","title":"Parcel Count","description":"Number of parcels the aggregate was computed over."},"typical_loan_usd":{"type":"integer","title":"Typical Loan Usd","description":"Opening balance for a 10%-down buyer of an average local home."},"typical_pmi_monthly_usd":{"type":"integer","title":"Typical Pmi Monthly Usd","description":"Monthly PMI for that buyer at a 0.85% annual rate."},"equity_gap_to_80_usd":{"type":"integer","title":"Equity Gap To 80 Usd","description":"Dollars between that buyer's 90% LTV start and the 80% HPA request threshold."},"source":{"type":"string","title":"Source","description":"The county record the aggregate derives from."},"source_publisher":{"type":"string","title":"Source Publisher","description":"Who publishes that record."},"method":{"type":"string","title":"Method","description":"The parcel filter applied, verbatim."},"computed_at":{"type":"string","title":"Computed At","description":"UTC timestamp of the computation, ISO 8601."},"max_age_hours":{"type":"integer","title":"Max Age Hours","description":"Age at which the aggregate is recomputed."},"page_url":{"type":"string","title":"Page Url","description":"Human-readable page for this ZIP code."},"disclaimer":{"type":"string","title":"Disclaimer"},"limitations":{"items":{"type":"string"},"type":"array","title":"Limitations"}},"type":"object","required":["zip_code","city","county","avg_value_usd","avg_sqft","price_per_sqft_usd","parcel_count","typical_loan_usd","typical_pmi_monthly_usd","equity_gap_to_80_usd","source","source_publisher","method","computed_at","max_age_hours","page_url","disclaimer","limitations"],"title":"MarketDataResponse","description":"City-level aggregate for one covered ZIP code, from county assessor records."},"PmiEligibilityRequest":{"properties":{"loan_balance":{"type":"number","exclusiveMinimum":0.0,"title":"Loan Balance","description":"Current unpaid principal balance on the mortgage, in USD."},"property_value":{"type":"number","exclusiveMinimum":0.0,"title":"Property Value","description":"Current market value of the property, in USD. The HPA's appreciation path is evaluated against this figure."},"year_purchased":{"anyOf":[{"type":"integer","maximum":2200.0,"minimum":1900.0},{"type":"null"}],"title":"Year Purchased","description":"Four-digit year the loan closed. Determines which appreciation-path threshold applies: loans under five years old are held to the stricter 75% figure. Omitted means unknown, which is treated conservatively as under five years."},"original_value":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Original Value","description":"Property value at origination, in USD. Supplied only to evaluate the HPA's original-value path (80% on request, 78% automatic) alongside the appreciation path. Optional."}},"type":"object","required":["loan_balance","property_value"],"title":"PmiEligibilityRequest","description":"Inputs for a PMI cancellation evaluation. No address, no identity."},"PmiEligibilityResponse":{"properties":{"ltv":{"type":"number","title":"Ltv","description":"Current loan-to-value ratio, as a decimal."},"ltv_pct":{"type":"number","title":"Ltv Pct","description":"Current loan-to-value ratio, as a percentage."},"equity_pct":{"type":"number","title":"Equity Pct","description":"Equity as a percentage of current property value."},"loan_age_years":{"type":"integer","title":"Loan Age Years","description":"Approximate loan age in years. Zero means unknown."},"zone":{"type":"string","enum":["green","yellow","red"],"title":"Zone","description":"green = at or below threshold; yellow = within reach; red = not yet."},"zone_label":{"type":"string","title":"Zone Label","description":"Human-readable name for the zone."},"threshold_ltv":{"type":"number","title":"Threshold Ltv","description":"The appreciation-path threshold that applies, as a decimal."},"citation":{"type":"string","title":"Citation","description":"Statutory citation for the applied threshold."},"meets_threshold":{"type":"boolean","title":"Meets Threshold","description":"Whether the current LTV is at or below the applied threshold."},"paydown_needed_usd":{"type":"integer","title":"Paydown Needed Usd","description":"Principal reduction needed to reach the applied threshold. Zero when met."},"appreciation_needed_usd":{"type":"integer","title":"Appreciation Needed Usd","description":"Property-value increase needed to reach the applied threshold, holding the balance fixed. Always the larger of the two. Zero when met."},"pathways":{"items":{"$ref":"#/components/schemas/HpaPathway"},"type":"array","title":"Pathways","description":"Every statutory path evaluated, including the original-value path when supplied."},"next_action":{"type":"string","title":"Next Action","description":"What the homeowner does next, given the result."},"statute":{"type":"string","title":"Statute","description":"The governing statute."},"hpa_effective_date":{"type":"string","title":"Hpa Effective Date","description":"The HPA applies to loans consummated on or after this date."},"disclaimer":{"type":"string","title":"Disclaimer","description":"What EquityUp is and is not."},"limitations":{"items":{"type":"string"},"type":"array","title":"Limitations","description":"Caveats that bound how this result should be used."}},"type":"object","required":["ltv","ltv_pct","equity_pct","loan_age_years","zone","zone_label","threshold_ltv","citation","meets_threshold","paydown_needed_usd","appreciation_needed_usd","pathways","next_action","statute","hpa_effective_date","disclaimer","limitations"],"title":"PmiEligibilityResponse","description":"A PMI cancellation evaluation under the federal Homeowners Protection Act."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}