Mortgage Decisions
Score a mortgage application against ability-to-repay and qualified mortgage rules. Combines cash-flow underwriting with DTI limits, LTV analysis, and independent property valuation. Returns a TILA-RESPA disclosure, or a decline with ECOA reason codes.
Create a decision
POST/v1/decisions/mortgageRequest body
| Field | Type | Description |
|---|---|---|
consumerRequired | object | Identifies the consumer. See Consumer object below. Either consumer_id (for returning customers) OR full PII fields (for new consumers). |
loanRequired | object | The mortgage terms requested. See Loan object below. |
propertyRequired | object | The subject property being financed. Used for LTV and valuation. See Property object below. |
Consumer object
| Field | Type | Description |
|---|---|---|
consumer_id | uuid | UUID of an existing consumer in your tenant. Skip the rest of the consumer fields if provided. |
first_name | string | Required for new consumers. |
last_name | string | Required for new consumers. |
email | string | Required for new consumers. Used for verification flows. |
phone | string | E.164 format. Used for SMS verification during hard KYC. |
dob | string | ISO 8601 date (YYYY-MM-DD). Required for new consumers. |
ssn_last4 | string | Last 4 digits of SSN. Required for hard KYC. Encrypted at rest. |
address | object | Current mailing address. Distinct from the subject property. |
Loan object
| Field | Type | Description |
|---|---|---|
amountRequired | decimal | Requested loan amount. Use a string to avoid floating-point issues. |
currencyRequired | string | ISO 4217 currency code. Currently only USD is supported. |
term_monthsRequired | integer | Requested term. Mortgages support 180 to 360 months (15 to 30 years). |
loan_purposeRequired | string | purchase, refinance, or cash_out_refinance. |
occupancy | string | primary_residence, second_home, or investment. Affects risk pricing. Defaults to primary_residence. |
Property object
| Field | Type | Description |
|---|---|---|
addressRequired | object | The subject property address. line1, city, state, zip required. Used for the ATTOM valuation lookup. |
property_typeRequired | string | single_family, condo, townhouse, or multi_family. |
purchase_priceRequired | decimal | Agreed purchase price (or appraised value for refinances). Used for LTV. |
down_payment | decimal | Down payment amount. Combined with purchase_price to compute LTV. |
Example request
Request body
{
"consumer": {
"first_name": "Robert",
"last_name": "Nakamura",
"email": "robert@example.com",
"phone": "+15553219876",
"dob": "1979-07-14",
"ssn_last4": "3310",
"address": {
"line1": "88 Beacon St",
"city": "Boston",
"state": "MA",
"zip": "02108"
}
},
"loan": {
"amount": 420000.00,
"currency": "USD",
"term_months": 360,
"loan_purpose": "purchase",
"occupancy": "primary_residence"
},
"property": {
"address": {
"line1": "12 Maple Ave",
"city": "Newton",
"state": "MA",
"zip": "02458"
},
"property_type": "single_family",
"purchase_price": 525000.00,
"down_payment": 105000.00
}
}Property valuation via ATTOM
Response
Mortgage decisions always run hard KYC given the loan size and regulatory requirements. The initial response is typically needs_consumer_action while the consumer completes identity verification and links financial accounts.
Approved
Status complete with outcome approved. The response includes ltv_pct, dti_pct, a qm_status flag, and the ATTOM property_valuation.
200 OK · approved
{
"decision_id": "e55f2c37-8b4a-4e1c-a2d9-3f5e7b2c8d44",
"application_id": "e55f2c37-8b4a-4e1c-a2d9-3f5e7b2c8d44",
"status": "complete",
"kyc_tier": "hard",
"kyc_status": "matched",
"outcome": "approved",
"score": 774,
"risk_grade": "A",
"approved_amount": "420000.00",
"currency": "USD",
"apr": "6.85",
"term_months": 360,
"monthly_payment": "2751.94",
"ltv_pct": "80.0",
"dti_pct": "34.2",
"qm_status": "qualified_mortgage",
"property_valuation": {
"source": "attom",
"estimated_value": "528000.00",
"confidence": "high"
},
"tila_disclosure": {
"amount_financed": "420000.00",
"finance_charge": "570698.40",
"total_of_payments": "990698.40",
"apr": "6.85",
"payment_frequency": "monthly"
},
"decline_reasons": [],
"expires_at": "2026-05-22T20:30:20.566665Z"
}Pending (hard KYC)
Status needs_consumer_action. The consumer must visit consumer_complete_url to complete verification and link accounts. Poll polling_url or wait for a webhook (coming Q3 2026).
200 OK · pending
{
"decision_id": "e55f2c37-...",
"application_id": "e55f2c37-...",
"status": "needs_consumer_action",
"kyc_tier": "hard",
"kyc_status": "pending",
"consumer_complete_url": "https://verify.altfiscore.com/c/e55f2c37...",
"polling_url": "/v1/decisions/mortgage/e55f2c37-8b4a-4e1c-a2d9-3f5e7b2c8d44",
"estimated_completion_seconds": 120,
"expires_at": "2026-05-22T21:00:00Z"
}Declined
Status complete with outcome declined. The decline_reasons array contains ECOA-compliant codes. DTI and LTV breaches are the most common mortgage declines. See compliance for adverse action handling.
200 OK · declined
{
"decision_id": "f66a3d48-...",
"application_id": "f66a3d48-...",
"status": "complete",
"outcome": "declined",
"score": 640,
"risk_grade": "C",
"dti_pct": "48.6",
"decline_reasons": [
{ "code": "AA-08", "reason": "Debt-to-income ratio exceeds the qualified mortgage limit of 43%." },
{ "code": "AA-14", "reason": "Loan-to-value ratio exceeds program limits for this credit tier." }
]
}A decline is still a 200
outcome: "declined". See the errors page for genuine error cases.Response fields
| Field | Type | Description |
|---|---|---|
decision_id | uuid | Unique identifier for this decision. Store for reconciliation and later lookup. |
application_id | uuid | Identifier for the underlying application. Typically equals decision_id for first-time decisions. |
status | string | complete or needs_consumer_action. |
kyc_tier | string | Mortgage decisions run hard KYC. |
kyc_status | string | matched, pending, or skipped. |
outcome | string | approved, declined, or referred. null when status is needs_consumer_action. |
score | integer | AltFiScore from 300 to 1000. |
risk_grade | string | Letter grade A+ through D derived from the score. |
approved_amount | decimal | String. The approved loan amount. |
apr | decimal | String. Annual percentage rate as a percentage. |
term_months | integer | Approved term in months. |
monthly_payment | decimal | String. Calculated monthly principal and interest. |
ltv_pct | decimal | String. Loan-to-value ratio as a percentage. |
dti_pct | decimal | String. Debt-to-income ratio as a percentage. |
qm_status | string | qualified_mortgage or non_qm. Indicates ATR/QM classification. |
property_valuation | object | ATTOM valuation: { source, estimated_value, confidence }. Advisory only. |
tila_disclosure | object | TILA-RESPA disclosure block ready to display to the consumer. |
decline_reasons | array | Array of { code, reason } objects. Populated when outcome is declined or referred. |
expires_at | timestamp | ISO 8601 timestamp. The offer or pending state expires at this time. |
Poll a decision
GET/v1/decisions/mortgage/{decision_id}Returns the current state of a previously-created decision. Idempotent and safe to call repeatedly. Recommended polling interval: 3–5 seconds given the longer verification window.
Poll a pending decision
curl 'https://api.altfiscore.com/v1/decisions/mortgage/e55f2c37-8b4a-4e1c-a2d9-3f5e7b2c8d44' \
-H 'Authorization: Bearer altfi_test_YOUR_KEY'Use idempotency
Errors
Returns standard HTTP error codes. The full catalog is in the errors reference. Most common errors for this endpoint:
400 invalid_request— required field missing (e.g., property.address)401 invalid_api_key— bad or missing API key409 idempotency_conflict— same idempotency key with a different body422 unprocessable_entity— request is well-formed but fails business rules (e.g., term outside 180–360 months)
Next steps
- Review the mortgage product page for QM rules and DTI limits
- Set up idempotent retries
- Handle declines with the compliance guide