---
title: "[RECOMMENDED] Get financing decision recommendations"
method: POST
path: "/v1/decisions"
tags: ["Primary - Decisions"]
---

# \[RECOMMENDED\] Get financing decision recommendations

`POST /v1/decisions`

## Request

- Base URL: `https://api.rateapi.dev`
- URL: `https://api.rateapi.dev/v1/decisions`
- Auth: API key in header `X-API-Key`

**This is the primary endpoint for production use.** Analyzes borrower context, product requirements, and current market offers to return ranked action recommendations with explanations. Transforms rate data into actionable decisions by comparing market rates, evaluating savings opportunities, and providing confidence scores.

**Supported Products:**
- **Mortgages**: 15-year and 30-year fixed-rate mortgages with property-specific details
- **Auto Loans**: New and used vehicle financing with common terms (36, 48, 60, 72, 84 months)

**Why use this endpoint:**
- **Personalized**: Considers borrower credit score, income, DTI, and product-specific details
- **Intelligent**: Ranks offers by suitability with confidence scores
- **Actionable**: Returns next steps and decision rationale
- **Comprehensive**: Includes savings calculations and comparison analysis

**Use Cases:**
- **Home purchase**: Compare credit union rates for new mortgage applications
- **Refinance**: Evaluate if refinancing makes financial sense given current offers
- **Auto loan shopping**: Find the best auto loan rates from credit unions for new or used vehicles
- **Rate shopping**: Get personalized recommendations based on borrower profile

**Authentication required**: Pass your API key in the `X-API-Key` header.

## Headers

- `Idempotency-Key` string

## Request body

- DecisionRequest: A decision request: what is being decided, the borrower and their geography, the product sought, any offer already in hand, and the caller’s preferences.
  - `decision_type` 'financing', required: Type of financing decision to make
  - `context` RequestContext, required: Envelope metadata for a decision request: schema version, caller-supplied request id, the as-of date to evaluate against, and the borrower’s geography.
    - `schema_version` string: API schema version for forward compatibility
    - `request_id` string: Unique identifier for this decision request. Used for tracing and idempotency.
    - `user_id` string: Optional user identifier for analytics and tracking
    - `as_of` string, date-time: ISO 8601 timestamp for when the decision should be calculated. Defaults to current time.
    - `geo` GeoContext, required: Where the borrower is, used to scope which institutions and rates can serve them.
      - `state` string, required: 2-letter US state code
      - `zip` string: US 5-digit ZIP or ZIP+4 (optional). When supplied, its crosswalk state must agree with `state`.
      - `county` string: Explicit county name for membership-eligibility geo matching (optional). Wins over ZIP-derived county candidates. A county-type suffix (e.g. ' County', ' Parish') is stripped during matching.
  - `borrower` BorrowerProfile: Optional borrower financial profile for personalized rate recommendations
    - `credit_score` integer: FICO credit score (300-850). Higher scores typically qualify for better rates.
    - `income_annual` number: Annual gross income in dollars. Used for debt-to-income calculations.
    - `employment` 'employed' | 'self_employed' | 'retired' | 'unemployed': Employment status affecting loan approval odds
    - `dti` number: Debt-to-income ratio as a decimal (e.g., 0.35 = 35%). Lower DTI improves approval chances.
    - `first_time_buyer` boolean: Whether this is a first-time home purchase. May qualify for special programs.
    - `veteran` boolean: Military veteran status. May qualify for VA loan programs.
    - `employer` string: Optional employer name for membership-eligibility SEG matching. Best-effort and positive-signal-only: a match can promote an offer to `eligible_via_employer`, but a non-match never asserts ineligibility.
    - `military_status` 'active_duty' | 'veteran' | 'reservist' | 'dod_civilian' | 'military_family': Optional military-affiliation fact for positive-only membership matching. A non-match never asserts ineligibility.
    - `school` string: Optional school, college, or university name for positive-only membership-affinity matching.
    - `school_relationship` 'student' | 'alumni' | 'employee': How the borrower relates to the named school. Required to affirm a typed student, alumni, or school-employee graph path.
    - `worship` string: Optional place-of-worship name for positive-only membership-affinity matching.
  - `product_request` ProductRequest, required: The product the borrower is asking about — type, intent, amount, term, and rate type.
    - `product_type` 'mortgage' | 'mortgage_arm' | 'auto_loan' | 'personal_loan' | 'heloc' | 'student_loan' | 'credit_card', required: Type of financing product. Currently 'mortgage' and 'auto_loan' are fully supported; other types will return appropriate messages. Use `mortgage_arm` for an adjustable-rate mortgage (5/1, 5/5, 7/1, 10/1, ...). ARMs are a separate market from fixed-rate mortgages: an ARM's introductory rate sits structurally below a comparable fixed rate, so a blended list would rank every ARM on top and present it as cheaper — true only until it resets. All initial fixed periods share one `mortgage_arm` bucket. Within `mortgage`, `term_months` selects 15- vs 30-year; it has no meaning for `mortgage_arm`.
    - `intent` 'purchase' | 'refinance' | 'cash_out' | 'balance_transfer' | 'new_credit': Purpose of the financing
    - `amount` number, required: Loan amount in dollars
    - `term_months` integer: Loan term in months. Optional - defaults to 360 (30-year) for mortgages, 60 (5-year) for auto loans. Common mortgage values: 180 (15-year), 360 (30-year). Common auto loan values: 36, 48, 60, 72, 84 months.
    - `rate_type` 'fixed' | 'adjustable' | 'variable': Interest rate structure
    - `details` ProductDetails: Additional details about the loan product for more accurate rate matching. Fields are product-specific: mortgage fields (property_type, occupancy, down_payment_percent, ltv) and auto loan fields (vehicle_condition, vehicle_year, vehicle_type).
      - `property_type` 'single_family' | 'condo' | 'townhouse' | 'multi_family': Type of property being financed (mortgage only)
      - `occupancy` 'primary' | 'secondary' | 'investment': How the property will be used. Primary residences typically get better rates. (mortgage only)
      - `down_payment_percent` number: Down payment as percentage of purchase price (0-100). Higher down payment typically means better rates. (mortgage only)
      - `ltv` number: Loan-to-value ratio as percentage (0-100). Lower LTV typically means better rates. (mortgage only)
      - `vehicle_condition` 'new' | 'used' | 'certified_pre_owned' | 'any': Condition of the vehicle being financed (auto_loan only). Use 'any' to match all conditions.
      - `vehicle_year` integer: Model year of the vehicle being financed (auto_loan only). Used to filter rates that apply to specific year ranges.
      - `vehicle_type` 'car' | 'truck' | 'suv' | 'motorcycle' | 'rv' | 'boat': Type of vehicle being financed (auto_loan only). Some rates may be specific to certain vehicle types.
  - `current_offer` CurrentOffer: Details of borrower's current loan or competing offer for comparison purposes
    - `provider_name` string: Name of current lender or competing institution
    - `amount` number, required: Current loan amount in dollars
    - `term_months` integer, required: Remaining term in months
    - `rate` number, required: Interest rate as percentage
    - `apr` number, required: APR as percentage including fees
    - `fees` number: Total closing costs or fees in dollars
  - `preferences` Preferences: Optional preferences to filter and customize recommendations
    - `max_providers` integer: Maximum number of lender offers to return per action
    - `prefer_credit_unions` boolean: Prioritize credit unions over banks in recommendations
    - `no_points` boolean: Filter out offers requiring discount points
    - `min_savings_monthly` number: Minimum monthly savings required to recommend refinance
    - `closing_timeline_days` integer: Expected timeline to close in days. May affect rate lock recommendations.
    - `max_fees` number: Maximum acceptable closing costs in dollars
    - `eligible_only` boolean: Compatibility preference (default false). Current behavior is annotation-only: offers are never dropped because no current membership payload carries a typed closed-world attestation. When true, the response reports `eligible_only_status: beta_annotation_only` and explains this limitation.
    - `include_institution_context` boolean: Opt in to compact, source-labelled NCUA institution facts on each final offer. Adds one bounded profile read over only the returned institutions.
    - `include_out_of_state` boolean: Opt in to documented out-of-state open or multi-state credit-union candidates. Default false preserves the historical requested-state candidate set.

## Response `200`

Decision recommendations with ranked actions

- DecisionResponse: A decision result: the summary verdict, the ranked actions with their supporting offers, and the disclosures that must be shown alongside them.
  - `request_id` string, required: Unique identifier for this decision (matches request)
  - `decision_type` 'financing', required: Type of decision made
  - `as_of` string, date-time, required: Timestamp when this decision was calculated
  - `summary` Summary, required: High-level decision summary
    - `recommended_action` 'shop_providers' | 'refinance' | 'lock_now' | 'wait_and_watch' | 'do_nothing', required: Top recommended action type
    - `confidence` number, required: Confidence in this recommendation (0-1)
    - `estimated_savings` object: Estimated savings from taking recommended action
      - `monthly` number: Monthly savings in dollars
      - `total` number: Total savings over loan term in dollars
    - `resolved_county` object: Present only when context.geo.county or a resolvable context.geo.zip was supplied (membership-eligibility geo matching). Omitted otherwise.
      - `county` string, required: Resolved county name (type suffix stripped)
      - `fips` string: 5-digit county FIPS code (present for ZIP-derived counties)
      - `source` 'explicit' | 'zip', required: Whether the county came from an explicit county field or ZIP derivation
  - `actions` Action[], required: Ranked list of recommended actions
    - `type` 'shop_providers' | 'refinance' | 'lock_now' | 'wait_and_watch' | 'do_nothing', required: Type of recommended action
    - `priority` integer, required: Action priority ranking (1 = highest priority)
    - `score` number, required: Recommendation strength score (0-100)
    - `why` string[], required: Human-readable reasons supporting this recommendation
    - `tradeoffs` string[], required: Potential drawbacks or considerations for this action
    - `expected_outcome` ExpectedOutcome, required: Projected financial outcomes for this action
      - `rate_range` object: Expected interest rate range based on borrower profile
        - `min` number: Lowest expected rate
        - `max` number: Highest expected rate
      - `monthly_payment` number: Estimated monthly payment (principal + interest only)
      - `monthly_payment_delta` number: Change in monthly payment vs current offer (negative = savings)
      - `total_savings` number: Total estimated savings over loan term
      - `break_even_months` integer: Months until refinance costs are recovered (refinance only)
    - `offers` Offer[], required: Specific rate offers from credit unions supporting this action
      - `rank` integer, required: Ranking within this action (1 = best offer)
      - `credit_union_id` string, required: Unique identifier for the credit union
      - `credit_union_name` string, required: Full name of the credit union
      - `credit_union_url` string, uri, nullable, required: URL to the credit union's website. Use evidence.source_url for the page proving this published rate.
      - `rateapi_url` string, uri, nullable: Link to this credit union's profile page on rateapi.dev (null if unresolvable)
      - `state` string, required: US state where credit union is located
      - `product_type` string, required: Type of mortgage product
      - `product_name` string, required: Specific product name
      - `display_name` string, nullable: Readable product label; product_name is the raw source name
      - `loan_program` string: Loan program type (e.g., conventional, FHA, VA, USDA, jumbo). Only present for mortgage products.
      - `rate` number, required: Interest rate as percentage
      - `apr` number, required: APR as percentage including fees
      - `points` number, required: Discount points required
      - `monthly_payment` number, required: Calculated monthly payment (P&I only)
      - `verification_confidence` number, nullable, required: Confidence score for rate accuracy (0-1). Null if unavailable.
      - `as_of` string, date-time, required: Observation time for this specific published rate. Alias of last_updated.
      - `last_updated` string, date-time, required: When this rate was last scraped
      - `evidence` object, required: Verbatim source proof for the published rate.
        - `source_url` string, uri, required: Credit-union page where this rate was observed.
        - `quote` string, required: Verbatim page excerpt supporting the published rate.
        - `proof_verified` true, required: Whether the retained proof passed RateAPI verification.
      - `estimated_monthly_savings` number: Estimated monthly savings vs current offer
      - `estimated_total_savings` number: Estimated total savings over loan term
      - `eligibility` Eligibility: Membership-eligibility guidance for this credit union (design doc §4). Present only when the CU has a cu_eligibility record; absent otherwise. Guidance based on public charter data and institution websites — final determination is made by the institution. Current open-world records never assert ineligibility.
        - `status` 'open_to_anyone' | 'likely_eligible' | 'eligible_via_employer' | 'eligible_via_military' | 'geo_mismatch' | 'unknown', required: Eligibility assessment. `open_to_anyone`: a documented open path matched. `likely_eligible`: positive geo, school, worship, or occupation evidence matched. `eligible_via_employer`: the supplied employer matches a verified SEG list. `eligible_via_military`: the supplied military affiliation matches. `unknown`: cannot be determined from available data, including geographic non-matches. `geo_mismatch` is retained only for wire compatibility and is not emitted from current unattested records.
        - `join_path` string: Reserved legacy field. Current person-specific offer annotations omit unbound flat join paths; use graph-backed eligibility_explanation.conditions instead.
        - `eligibility_type` string, required: Legacy field-of-membership type on flat annotations. Graph-authoritative offer annotations use the neutral value `graph` rather than a stale flat path label.
        - `confidence` number, required: Flat-record confidence for legacy annotations; graph verdict confidence when an active publication is authoritative.
        - `matched_rule` object: The concrete rule that produced a positive `status`. Explanatory only — never present on `geo_mismatch` or `unknown` (those carry no positive rule).
          - `type` 'county' | 'state' | 'employer' | 'occupation' | 'military' | 'school' | 'worship' | 'association_open', required: Exact positive rule category: geographic county/state, employer, occupation, military, school, worship, or an open association path.
          - `detail` string: Human-readable specifics of the match (e.g. the matched county name or employer entry).
      - `eligibility_explanation` EligibilityExplanation: Deterministic person-specific eligibility explanation. Action conditions and access cost are present only for the one selected graph path when overall status is conditionally_eligible.
        - `status` 'eligible' | 'conditionally_eligible' | 'possibly_eligible' | 'unknown' | 'ineligible', required: Person-specific graph vocabulary. `ineligible` is reserved for compatibility and is not emitted without a future typed closed-world attestation.
        - `reason` string, required: Deterministic sentence explaining the status.
        - `conditions` string[]: The single selected path's remaining action. Present only when overall status is conditionally_eligible; alternative OR paths are never combined.
        - `access_cost_usd` number: Known nonnegative cost of the same selected conditional graph path. Absent means unknown, not free.
        - `evidence_url` string, uri: Legacy evidence page when no graph verdict is authoritative. Omitted for graph verdicts until graph paths carry source-bound evidence.
        - `legacy_status` string: Compatibility status projected from the same verdict.
        - `source` 'graph' | 'annotation' | 'authority_unavailable' | 'absent', required: Authority that produced the explanation.
        - `publication` EligibilityPublicationRef: Exact immutable active eligibility generation evaluated for this response.
          - `publication_id` integer, required: Database identifier of the active publication.
          - `ruleset_sha256` string, required: SHA-256 digest of the complete ordered rule set.
          - `activated_at` string, date-time, required: When this generation became serving authority.
          - `proposal_coverage` EligibilityProposalCoverage: How many model-proposed claims from the source page survived evidence verification. This is not an attestation that every real-world field-of-membership path is known.
            - `scope` 'source_page_model_proposals', required: Metric scope, explicitly limited to model proposals extracted from reviewed source pages.
            - `proposed_claims` integer, required: Claims proposed by extraction from the reviewed source pages.
            - `verified_claims` integer, required: Proposed claims that passed evidence verification.
            - `published_rules` integer, required: Verified graph rules published from the candidate.
            - `withheld_claims` integer, required: Proposed claims withheld because verification did not pass.
            - `proposal_survival` number, nullable, required: Verified claims divided by proposed claims, or null when no claims were proposed.
            - `withheld_reasons` object, required: Withheld claim counts grouped by machine-readable verification reason.
      - `true_cost` TrueCost: Total numeric ranking basis for an eligibility-evaluated offer: borrowing cost plus points plus any selected path-bound access cost. No-record offers keep this wire field absent, while the engine still uses an internal numeric baseline for total ordering.
        - `true_total_cost_usd` number, required: Borrowing cost plus points cost plus selected access cost.
        - `cost_of_borrowing_usd` number, required: Total borrowing cost over the modeled term, or the annual proxy.
        - `points_cost_usd` number, required: Dollar cost of discount points for the requested amount.
        - `access_cost_usd` number, required: Known one-time cost of the selected conditional access path; zero means none was known.
        - `basis` 'amortized_term' | 'annual_interest_proxy', required: Calculation basis used for borrowing cost.
        - `access_cost_breakdown` EligibilityAccessCost: Auditable path-bound access cost used in true-cost ranking.
          - `total_usd` number, required: Known total one-time cost of the selected access path.
          - `membership_fee_usd` number: Known membership-fee component, when path-bound.
          - `min_deposit_usd` number: Known minimum-deposit component, when path-bound.
          - `source` 'annotation' | 'graph' | 'none', required: Provenance of the cost; current personalized ranking emits only graph-bound costs.
      - `institution_context` InstitutionContext: Compact NCUA quarterly facts for relationship-aware offer comparison. Present only when explicitly requested and available.
        - `source` string, required: The dataset these institution facts came from.
        - `cycle_date` string, date, required: Quarter-end date of the call report cycle these facts describe.
        - `members` integer, nullable, required: Current members, or null when not reported.
        - `locations` integer, required: Number of branch locations reported.
        - `total_assets` number, nullable, required: Total assets in US dollars, or null when not reported.
        - `year_opened` integer, nullable, required: Year the credit union began operating, or null when not reported.
        - `services` object, required: The subset of reported services most relevant to acting on a decision.
          - `online_membership` boolean, nullable, required: True when membership can be applied for online, or null when not reported.
          - `online_loan_application` boolean, nullable, required: True when loans can be applied for online, or null when not reported.
          - `financial_counseling` boolean, nullable, required: True when financial counseling is offered, or null when not reported.
    - `explanations` Explanations, required: Explainability data showing how the decision score was calculated
      - `method_version` string, required: Version of the scoring methodology used
      - `signals` Signal[], required: Individual signals that contributed to the score
        - `name` string, required: Human-readable signal name
        - `value` union, required: Signal value used in calculation
          - string
          - number
        - `weight` number, required: Importance weight of this signal (0-1)
        - `contribution` number, required: Score contribution from this signal (0-100)
  - `disclosures` string[], required: Legal and informational disclosures
  - `eligible_only_status` 'beta_annotation_only' | 'active': Present only when `preferences.eligible_only` was requested. Current responses use `beta_annotation_only`: offers are annotated and never filtered. `active` is reserved for compatibility with a future typed closed-world attestation rollout.
  - `excluded_count` integer: Reserved compatibility field for a future attested filter. It is absent from current annotation-only responses.

## Other responses

- `400`: Invalid request - validation errors in request body
- `401`: Missing or invalid API key
- `422`: Idempotency-Key was reused with a different request body.
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/rateapi/apis/rate-api.md) · [All operations](https://skmtc.dev/rateapi/apis/rate-api/llms.txt) · [OpenAPI document](https://skmtc.dev/rateapi/apis/rate-api/revisions/06a6db76995f?raw)
