---
title: "Position an external quote in the live market distribution"
method: POST
path: "/v1/rate-sanity-check"
tags: ["Data & Analytics"]
---

# Position an external quote in the live market distribution

`POST /v1/rate-sanity-check`

## Request

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

Takes an externally-sourced quote (rate/APR) for a product in a state and reports where it falls in the live market APR distribution: percentile, min/median/max, a classification, and a plain-language note. It can also return named lower-rate alternatives and product-matched rates from credit unions with NCUA-reported branches near an optional ZIP. ZIP proximity is source-labelled and does not claim road distance. Also flags quotes below the per-product APR floor as likely data errors or teaser rates.

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

## Request body

- object
  - `product_type` 'auto_loan' | 'mortgage' | 'mortgage_arm' | 'heloc' | 'personal_loan' | 'student_loan' | 'equipment_loan' | 'credit_card', required: The market to score the quote against. Use `mortgage_arm` for an adjustable-rate mortgage (5/1, 5/5, 7/1, 10/1, ...) — ARM intro rates run structurally below fixed rates, so scoring an ARM against the fixed market makes an ordinary quote look market-leading. All initial fixed periods share ONE `mortgage_arm` bucket. Use `mortgage` for fixed-rate mortgages and set `term_months` to pick 15- vs 30-year.
  - `state` string, required: 2-letter US state code
  - `rate` number, required: The quoted nominal rate (percent).
  - `apr` number: Optional quoted APR (percent). Falls back to `rate` when omitted.
  - `fees` number: Optional quoted fees in dollars (surfaced in the note, not folded into APR).
  - `amount` number: Optional loan amount in dollars.
  - `term_months` integer: Optional loan term in months. For `mortgage`, this selects the comparison market: under 300 months scores against the 15-year distribution, 300+ against the 30-year. Ignored for `mortgage_arm`, which is a single bucket.
  - `vehicle_condition` string: For auto_loan only: 'used'/'certified_pre_owned'/'cpo' selects the used benchmark bucket; otherwise the new bucket is used.
  - `zip` string: Optional borrower ZIP. Used for membership context and, with include_nearby_offers, NCUA-reported branch proximity.
  - `include_better_offers` boolean: When true, include a bounded list of statewide offers currently beating the quote.
  - `include_nearby_offers` boolean: When true and zip is supplied, include product-matched rates from credit unions ranked by estimated distance to the closest NCUA-reported branch.

## Response `200`

Quote positioned against the live market distribution.

- object
  - `product_type` string: Loan or deposit product this applies to.
  - `state` string: Two-letter US state code.
  - `quote` object: The quote that was checked, echoed back.
    - `rate` number: Note rate as an annual percentage, excluding fees.
    - `apr` number: Annual percentage rate, which includes fees and is the figure offers are ranked on.
  - `percentile` integer: Percentile of the market the quote's APR sits at (0=best/lowest).
  - `classification` 'market_leading' | 'plausible' | 'suspicious_low' | 'overpriced' | 'unknown': Verdict on the quote: `market_leading` beats most of the market, `plausible` sits in the normal range, `suspicious_low` falls below the product floor and is likely a teaser or a misread, `overpriced` sits well above the median, `unknown` when there was no market to compare against.
  - `below_product_floor` boolean: True when the quoted APR falls below the lowest rate this product plausibly prices at, which usually means the figure is a promotional teaser or was misread.
  - `product_floor` number: The lowest APR this product plausibly prices at, as an annual percentage.
  - `market` object: Summary of the live offers the quote was compared against.
    - `min` number, nullable: Lowest APR among the offers compared against.
    - `median` number, nullable: Median APR among the offers compared against.
    - `max` number, nullable: Highest APR among the offers compared against.
    - `count` integer: How many offers the comparison was made against.
    - `as_of` string, nullable: When the underlying rates were published.
  - `note` string: Plain-language explanation of what this result means.
  - `better_offers` object[]: Present only when `include_better_offers` is true: lenders currently beating the quote. Minimal schema — the naming fields are documented because they changed meaning in 2026-07; the remaining fields are additive.
    - `credit_union_name` string: Name of the credit union.
    - `product_name` string, nullable: The lender's own name for the product, verbatim from its rate page. ⚠️ CHANGED 2026-07-29: this field previously carried the DERIVED label when one existed. It is now always the raw source name; the derived label moved to `display_name`.
    - `display_name` string, nullable: Readable product label; product_name is the raw source name. Falls back to product_name.
    - `apr` number: Annual percentage rate, which includes fees and is the figure offers are ranked on.
    - `apr_delta_bps` integer: How much cheaper than the quote, in basis points.
    - `estimated_monthly_savings` number: How much less this offer would cost per month than the quote, in US dollars.
    - `can_you_join` 'yes' | 'likely' | 'unknown' | 'no': Whether the borrower can join this credit union, based on its extracted membership rules. `unknown` means no rule was found, never that they are ineligible.
  - `nearby_offers` object[]: Present when include_nearby_offers is true and zip is supplied. Institutions rank by estimated distance to the closest reported branch, then by APR.
    - `credit_union_id` string: Canonical identifier of the credit union.
    - `credit_union_name` string: Name of the credit union.
    - `rateapi_url` string, nullable: Page on rateapi.dev covering this credit union.
    - `product_name` string: The lender's own name for the product, verbatim from its rate page.
    - `display_name` string: Readable product label derived from the classified product facts. Falls back to `product_name`.
    - `rate` number: Note rate as an annual percentage, excluding fees.
    - `apr` number: Annual percentage rate, which includes fees and is the figure offers are ranked on.
    - `apr_delta_bps` integer: Quote APR minus local-offer APR in basis points. Positive means the local offer is cheaper.
    - `comparison` 'lower' | 'same' | 'higher': How this local offer’s APR compares to the quote.
    - `proximity` 'same_zip' | 'distance' | 'nearby_zip_prefix': How this credit union was matched to the ZIP code: a branch in the same ZIP, a measured distance, or a shared ZIP prefix.
    - `distance_miles` number, nullable: Straight-line distance to the closest reported branch, or null when no distance could be computed.
    - `distance_method` 'branch_coordinate' | 'zip_centroid' | 'null', nullable: What the distance was measured from — a branch coordinate or the ZIP centroid — or null when no distance was computed.
    - `branch` object: The reported branch the distance was measured to.
  - `nearby_offers_meta` object: How the local search was scoped, and why it returned nothing when it did.
    - `nearby_credit_union_count` integer: Credit unions found near the ZIP code before offers were matched.
    - `precision` string: How the distances were computed, stated in words so they cannot be mistaken for driving distance.
    - `disclosure` string: Statement that must be shown to a consumer alongside this result.
    - `unavailable_reason` string: Why no local offers were returned. Present only when the list is empty.

## Other responses

- `400`: The request was malformed — a missing required field, an unparseable body, or a parameter outside its allowed range. The `error` field names what was wrong; retrying the identical request will fail identically.
- `401`: No API key, or a key that is unknown or disabled. Send it in the `X-API-Key` header. Free keys are issued instantly by POST /keys with an email address. The response carries `WWW-Authenticate` pointing at this host's protected-resource metadata, and the `RateLimit-*` headers describing the Free-tier budget a key issued now would carry (scope `anonymous`) — a rejected request spends none of it, so `Remaining` equals `Limit`.
- `429`: Quota exhausted for the current window. `Retry-After` gives the seconds to wait; `upgradeInfo` explains how to lift the cap. Retrying before the reset will fail again and still counts as a request.

---

[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)
