---
title: "Get Fair Market Value (FMV) by Certificate Number"
method: POST
path: "/v1/cards/fmv-by-cert"
tags: ["Pricing & Valuations"]
---

# Get Fair Market Value (FMV) by Certificate Number

`POST /v1/cards/fmv-by-cert`

## Request

- Base URL: `https://api.cardhedger.com`
- URL: `https://api.cardhedger.com/v1/cards/fmv-by-cert`
- Auth: API key in header `X-API-Key`

Get the Fair Market Value (FMV) for a card by grader certificate number.

Convenience wrapper that chains a certificate lookup into an FMV
valuation, so callers holding only a cert number do not need to resolve
the card themselves.

## How it works

1. Checks the persistent validated-certificate cache; queries GemRate only
   when that certificate has not been successfully retrieved before.
2. Resolves the card in CardHedge using the GemRate IDs.
3. Fallback: if step 2 finds no card, matches the GemRate description
   against the AI `card-match` endpoint.
4. Requests the FMV for the resolved card at the certificate's grade.

## Card resolution (`card_source` / `match_confidence`)

- `card_source: "gemrate_id"` — direct GemRate ID → CardHedge lookup
  succeeded. `match_confidence` is null.
- `card_source: "card_match"` — direct lookup found nothing; the card
  was matched from the GemRate description via the AI fallback.
  `match_confidence` (0-1) is the matcher's score; **treat an FMV
  derived from a low-confidence match with care**. Cards resolved this
  way have null `category_group` and `set_type` because the matcher
  doesn't return those two fields.

## FMV (`fmv`)

The `fmv` object is identical to the `/v1/cards/card-fmv` response — see
that endpoint for the full method cascade (`direct`, `card_interpolation`,
`cross_provider`, `anchor_multiplier`, `segment_fallback`, `no_data`),
`_indexed` variants, confidence grading, and movement-index metadata.

## When fields are null

- `card` and `fmv` are both null only when the certificate cannot be
  matched to a card by EITHER the GemRate ID lookup or the description
  fallback.
- When the card is found but the upstream has insufficient sale data,
  `fmv` is a populated object with `method: "no_data"` and `price: null`
  — `card` is still populated in this case.

**Example curl:**
```bash
curl -X POST -H "X-API-Key: your-api-key-here" \
     -H "Content-Type: application/json" \
     -d '{
       "cert": "50000000",
       "grader": "PSA"
     }' \
     "https://api.cardhedger.com/v1/cards/fmv-by-cert"
```

**Daily allowance of uncached lookups.** The first time a certificate is looked up it needs a live call to our grading-data provider and draws on your account's daily allowance of such lookups; repeat lookups are served from cache and do not. See *Rate limits* in the API overview for your tier's allowance.

## Request body

- FMVByCertRequest: Request parameters for the FMV-by-certificate endpoint.
  - `cert` string, required: Certificate number to look up
  - `grader` string: Grading company (defaults to PSA)

## Response `200`

Successful Response

- FMVByCertResponse: Response model for the FMV-by-certificate endpoint.
  - `cert_info` GemRateCertInfo, required: Certificate verification information.
    - `grader` string, required: Grading company (e.g., PSA, BGS, CGC)
    - `cert` string, required: Certificate number
    - `grade` string, required: Card grade (e.g., PSA 10, BGS 9.5)
    - `gemrate_id` string, nullable: Unique card identifier
    - `universal_gemrate_id` string, nullable: Universal card identifier
    - `description` string, nullable: Card description from certificate
  - `card` CardDetails: Detailed card information and metadata.
    - `card_id` string, required: Unique card identifier
    - `description` string, nullable: Full card description
    - `player` string, nullable: Player or character name
    - `set` string, nullable: Card set name
    - `number` string, nullable: Card number in set
    - `variant` string, nullable: Card variant (e.g., Base, Refractor, Prizm)
    - `image` string, nullable: Card image URL
    - `category` string, nullable: Card category (e.g., Baseball, Basketball, Pokemon)
    - `category_group` string, nullable: Category group, derived from the catalog category for indexed cards
    - `set_type` string, nullable: Set type, derived from the catalog set name for indexed cards
  - `fmv` CardFMVResponse: Response model for the card FMV endpoint. Mirrors the upstream FMV service response. Any additional fields returned by the upstream are preserved via ``extra='allow'`` so consumers receive the full payload even if the upstream adds new fields.
    - `price` number, nullable: Fair market value in USD (null when no data available)
    - `price_low` number, nullable: Lower bound of the FMV range (null when no data available)
    - `price_high` number, nullable: Upper bound of the FMV range (null when no data available)
    - `confidence` number, nullable: Confidence score (0-1) for the FMV calculation
    - `method` string, nullable: FMV calculation method. One of 11 values from the cascade: **Base methods (in priority order):** - `direct` — Exact card+grade lookup. Latest_price is replaced with a Winsorized-median FMV over a 7/15/30/90-day window when enough daily prints exist; otherwise latest_price is used as-is. - `card_interpolation` — No direct price; isotonic regression in log-space across the card's OTHER same-provider grades, then interpolating/extrapolating to the target grade. - `cross_provider` — No same-provider data; translates from another grader (e.g., BGS 9 → PSA 9) using a learned price ratio. - `anchor_multiplier` — Uses one same-provider grade as an anchor and applies a within-provider grade multiplier. Variants include same-provider, chained (e.g., BGS 8.5 → BGS 9 → PSA 9), and raw (Raw card price → graded). See `anchor_from_raw` / `anchor_chained_from_provider`. - `segment_fallback` — Last resort: uses the set/year × category baseline price and applies a grade multiplier. - `no_data` — No sale data could produce a value; `price` is null. **`_indexed` variants** (`direct_indexed`, `card_interpolation_indexed`, `cross_provider_indexed`, `anchor_multiplier_indexed`, `segment_fallback_indexed`) — the base method produced a stale price, so a movement index was overlaid to bring it to today. See `index_level`, `index_pct_change`, and `raw_price` for the adjustment details.
    - `freshness_days` integer, nullable: Age of the underlying sale data in days (0 = today). On `_indexed` methods this reflects the index's `as_of_date`, not the base price's age. Null on `segment_fallback` and `no_data`.
    - `support_grades` integer, nullable: Number of grade data points contributing to the estimate. 1 for `direct`; 2+ for `card_interpolation` (other grades of this card); 1 for `anchor_multiplier`; 0 for `segment_fallback` / `no_data`.
    - `grade_label` string, nullable: Normalized grade label the FMV was computed for (e.g., 'PSA 9', 'BGS 9.5', 'Raw').
    - `provider` string, nullable: Grading provider (e.g., 'PSA', 'BGS', 'SGC', 'CGC', 'Raw').
    - `grade_value` number, nullable: Numeric grade value (e.g., 9.0, 9.5, 10.0). 0 for Raw; negative values denote authenticated-only grades (e.g., 'PSA Auth').
    - `as_of_date` string, nullable: ISO 8601 date the applied movement index was last computed. Set only on `_indexed` methods; null otherwise.
    - `index_level` string, nullable: Cascade level used for movement adjustment. One of: - `card_grade` — most specific: this card at this grade - `card` — blended across all grades of this card - `player` — player-level index (all cards of this player) - `segment` — (year × category) segment-level index - `none` — stale price, but no index met the minimum sample threshold (an `un_indexed_penalty` is applied to confidence) - `null` — fresh estimate, no movement adjustment needed
    - `index_pct_change` number, nullable: Cumulative percent change applied by the movement index over the FMV's lookback window (decimal, e.g., 0.157 = +15.7%). Set only on `_indexed` methods.
    - `raw_price` number, nullable: Pre-adjustment price in USD. For `direct`: the chosen FMV value (or the original `latest_price` when no FMV qualified). For other cascade methods: the original method result before any movement adjustment. Compare `price` vs `raw_price` to see what the movement index changed.
    - `index_truncated` boolean, nullable: True if the FMV's lookback window was capped at the maximum (730 days) because the underlying price was extremely stale. Treat truncated movement adjustments as lower-confidence.
    - `fmv_window_days` integer, nullable: FMV smoothing window used for the base price. One of 7, 15, 30, or 90 — the upstream picks the shortest window with enough samples. Null when no FMV smoothing was applied (the lookup fell back to `card_grade_prices.latest_price`, or the method is not `direct`).
    - `fmv_sample_count` integer, nullable: Number of distinct daily prints that fed the chosen FMV's Winsorized median. Higher = more reliable. Null when no FMV was applied.
    - `base_sample_count` integer, nullable: Number of sales behind the base latest_price (90-day sale count on the source grade row). Only set on `direct` lookups that did NOT substitute a Winsorized-median FMV — where `fmv_sample_count` is present it describes the FMV instead. Use to tell a well-backed latest_price from a single-sale print; null means the source reported no sale count.
    - `index_sample_count` integer, nullable: Number of observations at the chosen movement-index window. Useful for filtering low-signal adjustments — e.g., ignore `index_pct_change` when `index_sample_count < 10`.
    - `confidence_grade` string, nullable: Bucketed confidence grade — a quick proxy for the numeric `confidence`: - `A` — confidence ≥ 0.42 (~86% of prices within 2× of the actual sale). Trust for valuations. - `B` — confidence ≥ 0.25 (~74% within 2×). Usable; consider showing `raw_price` too. - `C` — confidence ≥ 0.10 (~63% within 2×). Borderline; consider falling back to `latest_price` for sensitive decisions. - `D` — confidence < 0.10 (~49% within 2×). Likely noisy; show with disclaimer. Cutoffs are calibrated to measured accuracy on held-out sales and may be re-tuned as the model improves — rely on the letter grade rather than hard-coding numeric thresholds. Null on `no_data`. The numeric `confidence` already folds in cascade method, FMV signal strength, and movement-index quality, so this single grade reflects total trust in the returned price.
    - `price_explanation` string, nullable: Human-readable description of how the FMV was derived — e.g., 'Used 7d FMV ($416.25, Winsorized median of 3 daily prints) in place of latest_price $416.25. Fresh (1d) — no movement adjustment applied.' Useful for debug UIs and audit trails; not intended for programmatic parsing (wording may change).
    - `cross_grade_fmv_count` integer, nullable: For cross-grade methods (`card_interpolation`, `cross_provider`, `anchor_multiplier`): count of source grades whose `latest_price` was replaced with a Winsorized-median FMV before the cascade ran. Higher = more smoothing applied. Null when the method wasn't used; 0 when used but no FMV qualified for any source.
  - `card_source` string, nullable: How the card was resolved: 'gemrate_id' for a direct GemRate ID -> CardHedge lookup, or 'card_match' when that lookup found nothing and the card was matched from the GemRate description via the AI card-match fallback. Null when no card was resolved. Cards resolved via 'card_match' have null 'category_group' and 'set_type' -- the matcher does not return those two fields.
  - `match_confidence` number, nullable: AI match confidence (0-1) when 'card_source' is 'card_match'; null otherwise. Treat an FMV derived from a low-confidence match with care.

## Other responses

- `422`: Validation Error
- `429`: Daily allowance of uncached certificate lookups used up. Each account may look up a limited number of certificates not seen before per day; certificates already looked up are still served from cache. Resets at 00:00 UTC; see the `Retry-After` and `X-RateLimit-*` headers. Batch endpoints return this only when no certificate in the batch could be served; otherwise they mark unserved certificates with `error: gemrate_daily_quota_exceeded`. Contact sales at support@cardhedger.com for a higher allowance.

## Changes

- **2026-10-05** `a7e88a62d4ba`: 1 info
  - added the non-success response with the status `429`

[Operation history](https://skmtc.dev/cardhedger/apis/card-hedge-api/changes/v1/cards/fmv-by-cert/post.md)

---

[API](https://skmtc.dev/cardhedger/apis/card-hedge-api.md) - [All operations](https://skmtc.dev/cardhedger/apis/card-hedge-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cardhedger/apis/card-hedge-api/revisions/6de42f192a4d?raw)
