Market
Market metrics over time
Authorization
Body application/json
advancedFiltersone ofShow child attributesHide child attributes
Option 1objectShow child attributesHide child attributes
childrenone of[]requiredArray of filter expressions (AND)
Same shape as its parent.
typeenumrequiredandOption 2objectShow child attributesHide child attributes
childrenone of[]requiredArray of filter expressions (OR)
Same shape as its parent.
typeenumrequiredorOption 3objectShow child attributesHide child attributes
childone ofrequiredSame shape as its parent.
typeenumrequirednotOption 4objectShow child attributesHide child attributes
fieldstringrequiredopenumrequiredComparison operator. exists means the field has a REAL value: on fields whose source records an unknown as an in-domain value (e.g. beds, squareFeet, lotSquareFeet, where an unrecorded measurement is stored as 0), those docs count as NOT existing. neq keeps docs with no value — it removes only what is known to equal the value, matching the reading of an exclusion.
eqneqgtgteltltebetweeninmatchgeoDistanceexiststypeenumrequiredfiltervaluenullComparison value
filtersone ofShow child attributesHide child attributes
Option 1objectShow child attributesHide child attributes
childrenone of[]requiredArray of filter expressions (AND)
Same shape as its parent.
typeenumrequiredandOption 2objectShow child attributesHide child attributes
childrenone of[]requiredArray of filter expressions (OR)
Same shape as its parent.
typeenumrequiredorOption 3objectShow child attributesHide child attributes
childone ofrequiredSame shape as its parent.
typeenumrequirednotOption 4objectShow child attributesHide child attributes
fieldstringrequiredopenumrequiredComparison operator. exists means the field has a REAL value: on fields whose source records an unknown as an in-domain value (e.g. beds, squareFeet, lotSquareFeet, where an unrecorded measurement is stored as 0), those docs count as NOT existing. neq keeps docs with no value — it removes only what is known to equal the value, matching the reading of an exclusion.
eqneqgtgteltltebetweeninmatchgeoDistanceexiststypeenumrequiredfiltervaluenullComparison value
flatFiltersobjectShow child attributesHide child attributes
amortizationTypeone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredappraisedValueone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberborrowerGenerationone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredchannelone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredclosingDateone of | nullShow child attributesHide child attributes
Option 1stringExact date, or a whole period: YYYY-MM-DD (that day), YYYY-MM (the whole month — "2025-06" = 2025-06-01 through 2025-06-30) or YYYY (the whole year). YYYYMMDD, MM/DD/YYYY, an ISO-8601 datetime and epoch milliseconds are also accepted. An unparseable value is a 400.
Option 2objectDate range. Excludes null/missing-field docs by default; add includeNulls: true to keep them. Bounds accept YYYY, YYYY-MM, YYYY-MM-DD, YYYYMMDD, MM/DD/YYYY, a full ISO datetime or epoch milliseconds; an unparseable bound is a 400. A partial bound denotes the whole period and expands to the edge that preserves the operator: gte/lt take the period START, gt/lte take the period END — so {gte: "2024"} means on/after 2024-01-01 and {lte: "2024"} means through 2024-12-31.
Show child attributesHide child attributes
gtstringgtestringincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires a bound.
ltstringltestringcombinedLtvone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumbercommunityIncomeLevelone of | nullFFIEC income classification of the neighborhood the property sits in. A tract-level aggregate statistic describing the neighborhood, never an individual, household or applicant attribute. Carried on roughly a fifth of originations, so this filter narrows sharply.
Show child attributesHide child attributes
Option 1enumOne of (case-insensitive): low, moderate, middle, upper
lowmoderatemiddleupperOption 2enum[]Match any of these values
lowmoderatemiddleupperOption 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredcountyone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredcountyCodeone of | null3-digit county code (the county segment of a FIPS, e.g. Philadelphia = "101"). Pair it with state — the code is not unique across states. county accepts a county NAME or 5-digit FIPS and resolves to this code for you.
Show child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredcraEligiblebooleanOnly CRA-eligible originations (a low- or moderate-income neighborhood OR a low- or moderate-income borrower). Determined on every origination.
creditScoreone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumbercurrentHomeOwnerboolean | nulldtione of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberdtifrontone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberfirstTimeHomebuyerboolean | nullhmdaActionTakenone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredincomeone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberloanAmountone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberloanApplicationDateone of | nullShow child attributesHide child attributes
Option 1stringExact date, or a whole period: YYYY-MM-DD (that day), YYYY-MM (the whole month — "2025-06" = 2025-06-01 through 2025-06-30) or YYYY (the whole year). YYYYMMDD, MM/DD/YYYY, an ISO-8601 datetime and epoch milliseconds are also accepted. An unparseable value is a 400.
Option 2objectDate range. Excludes null/missing-field docs by default; add includeNulls: true to keep them. Bounds accept YYYY, YYYY-MM, YYYY-MM-DD, YYYYMMDD, MM/DD/YYYY, a full ISO datetime or epoch milliseconds; an unparseable bound is a 400. A partial bound denotes the whole period and expands to the edge that preserves the operator: gte/lt take the period START, gt/lte take the period END — so {gte: "2024"} means on/after 2024-01-01 and {lte: "2024"} means through 2024-12-31.
Show child attributesHide child attributes
gtstringgtestringincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires a bound.
ltstringltestringloanPurposeone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredloanStatusone of | nullHMDA action, else funding/denial/lock date evidence.
Show child attributesHide child attributes
Option 1enumOne of (case-insensitive): funded, purchased, not_funded, pending
fundedpurchasednot_fundedpendingOption 2enum[]Match any of these values
fundedpurchasednot_fundedpendingOption 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredloanTermone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberloanTypeone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredlowModIncomeTractbooleanOnly originations in a low- or moderate-income neighborhood. This describes the U.S. Census tract (neighborhood) as a whole — a tract-level aggregate statistic, never an individual, household or applicant attribute. false also matches originations whose neighborhood carries no income classification; pair with communityIncomeLevel when you need the classified population only.
ltvone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumbermajorityMinorityTractbooleanOnly originations in a majority-minority neighborhood. This describes the U.S. Census tract (neighborhood) as a whole — a tract-level aggregate statistic, never an individual, household or applicant attribute. Carried on about half of originations.
metroone of | nullMetro area code (5-digit federal CBSA code, e.g. Los Angeles = "31084"). Roughly half of originations sit outside any metro area and carry no code, so a metro filter is a narrowing one.
Show child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredmiddleIncomeTractbooleanOnly originations in a middle-income neighborhood. Tract-level aggregate, never an individual attribute. Same caveat on false as lowModIncomeTract.
minorityTractPctone of | nullNon-white share (0-100) of the neighborhood's population. Tract-level aggregate, never an individual attribute.
Show child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumbermodeenumandornoteRateone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberoccupancyTypeone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredpropertyTypeone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredpurchasePriceone of | nullShow child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberselfEmployedboolean | nullstateone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredtractIncomeVsMetroPctone of | nullNeighborhood median family income as a percent of its metro area's — 100 is parity, and it legitimately exceeds 100. Tract-level aggregate, never an individual attribute.
Show child attributesHide child attributes
Option 1numberOption 2number[]Match any value
Option 3objectNumeric range. Excludes null/missing-field docs by default; add includeNulls: true to keep them.
Show child attributesHide child attributes
gtnumbergtenumberincludeNullsbooleanAlso keep docs where the field is null/missing (a range filter drops them by default). Requires at least one of gte/lte/gt/lt.
ltnumberltenumberveteranIndicatorboolean | nullzipone of | nullShow child attributesHide child attributes
Option 1stringOption 2string[]Match any value
Option 3objectFuzzy text match
Show child attributesHide child attributes
matchstringrequiredforecastobjectAppend a zero-shot forecast (Amazon Chronos-2) to the time series. Monthly interval only. The history in current is returned unchanged; the forecast starts the month after forecast.asOf.
Show child attributesHide child attributes
horizonintegerdefault: 6Months ahead to forecast, counted from asOf (1–12).
scenarioobjectdefault: {"rate30y":"hold"}Known-future covariates the forecast conditions on. Omit for hold.
Show child attributesHide child attributes
rate30yone ofdefault: "hold"Path of the 30-year fixed mortgage rate over the forecast horizon, one value per month, as a plain percent (6.5 = 6.5%). Presets: hold keeps the latest weekly Freddie Mac PMMS reading flat; fall glides it down 1.0 point linearly over the horizon; rise glides it up 1.0 point. An explicit array must have exactly horizon entries. The rate is an INPUT the model conditions on, never something it predicts.
Show child attributesHide child attributes
Option 1enumholdfallriseOption 2number[]intervalenumweeklymonthlyquarterlyyearlymeasureenumWhich metric to compute. Every field-backed measure is sentinel-guarded: the source encodes unknown values as an out-of-range fill, so values outside the measure's plausible range are dropped before it is aggregated. Ranges: volume 0–100,000,000; avgRate 0–25; avgLoanAmount 0–100,000,000; avgCreditScore 300–850; avgLTV 0–999; avgDTI 0–999; avgIncome 0–100,000,000; avgAppraisedValue 0–100,000,000; avgPurchasePrice 0–100,000,000; avgDtiFront 0–999; avgCombinedLtv 0–999; avgLoanTerm 0–1,200; originatedVolume 0–100,000,000; originatedAvgDti 0–100. units and originatedUnits are document counts and are not guarded. Each response reports how many documents its guard excluded, so a mean taken over 98% of the data can be told apart from one taken over 60%. NOTE on population: units and volume cover loan APPLICATIONS of every outcome — denials, withdrawals and secondary-market purchases included — and so does avgDTI, while originatedUnits, originatedVolume and originatedAvgDti cover originations only.
volumeunitsavgRateavgLoanAmountavgCreditScoreavgLTVavgDTIavgIncomeavgAppraisedValueavgPurchasePriceavgDtiFrontavgCombinedLtvavgLoanTermoriginatedUnitsoriginatedVolumeoriginatedAvgDtiperiodenumDate window for loans / sales / market endpoints. Accepts every Period value plus rolling windows: last30Days / last60Days / last90Days (today minus 30 / 60 / 90 days through today), previousMonth (the last complete calendar month) and currentMonth (the 1st of this month through today). All windows are resolved in UTC with inclusive calendar-date bounds. Rolling windows are only accepted by the loans, sales and market endpoints (list, count, breakdowns, analytics summary / time-series / chart); originators / companies / branches / agents / offices endpoints return 400 for them.
2017201820192020202120222023202420252026last3Monthslast6Monthslast12Monthslast14Monthslast16Monthslast18Monthslast24MonthsyearToDateallTimelast30Dayslast60Dayslast90DayspreviousMonthcurrentMonthsegmentenumstatecountymetroziploanPurposeloanTypepropertyTypeoccupancyTypeamortizationTypechannelborrowerGenerationfirstTimeHomebuyerveteranIndicatorhmdaActionTakenselfEmployedcurrentHomeOwnerlenderTypelenderVolumeClassResponses
200objectTime series with previous-period comparison. Each bucket carries `volume`, `units`, and `measureValue` for the requested `measure`. With `forecast` in the request, a `forecast` block is appended.Show attributesHide attributes
completenessobjectData-completeness watermark for this response. Present only when it could be measured; absence means it was not measured, NOT that the data is complete.
Show child attributesHide child attributes
throughdaterequiredThe last calendar date (YYYY-MM-DD) this query's matching records actually reach. Records arrive after the events they describe, so a period ending today is normally backed by data ending days or weeks earlier, and any bucket extending past this date is built from a partial period. Measured from THIS query's own matched set, not a global figure: the delay varies by geography and moves over time, so two requests with different filters can legitimately report different dates.
currentobject[]requiredShow child attributesHide child attributes
completebooleanWhether this bucket's whole period is backed by data. false means the bucket extends past completeness.through, so it is built from a partial period and MUST NOT be compared against its neighbours or the same bucket a year earlier. Absent whenever completeness itself is absent; the two are emitted together or not at all.
datestringrequiredexcludednumberHow many of this bucket's documents the requested measure's sentinel guard excluded — documents carrying the field whose value is an out-of-range fill. Compare against units to see the share the value was computed over. Present per BUCKET because exclusion is not uniform over time: one period can be almost entirely fill values while its neighbors are clean, and a single response-level total would hide exactly that. Absent for units, which is a document count and cannot be guarded.
measureValuenumber | nullrequiredThis bucket's value for the requested measure (volume when none was supplied). Null when the bucket has no in-bounds document for the measure's field — sentinel-filtered rows do not contribute, so an empty bucket reports null rather than 0.
segmentsobject[]Show child attributesHide child attributes
labelstringrequiredmeasureValuenumber | nullrequiredThis segment's value for the requested measure. Null when the segment has no in-bounds document for the measure's field.
unattributedenumPresent and true on at most one segment PER DATE BUCKET, which is not a real category: it collects the documents that bucket could not attribute to any value of the requested segment, and its label ("(unknown)") is prose, not an identifier. Filter on THIS field, never on the label — a consumer joining a segment label to a real code must drop it. It is always the LAST entry of its bucket's segments, appended after ranking rather than placed by value, so it is the one segment that does not obey the ordering measure describes. It exists so a period's segments account for the same documents that period's own units counts: a document whose segment field holds no indexed term is absent from a terms breakdown entirely rather than forming a small segment, so without it a stacked series silently omits part of every bar. That reconciliation is exact for units; on an average it is not, because segments under the five-document floor are dropped and a segment field with more than 200 distinct values still truncates — neither loss is collected here. Reported per bucket rather than once per response because what cannot be attributed is not uniform over time. Absent when there is nothing unattributed, never false and never a zero-valued segment.
trueunitsnumberrequiredvolumenumberrequiredunitsnumberrequiredNumber of loans
volumenumberrequiredTotal loan volume in dollars
forecastobjectPresent only when the request carried forecast. History above is unchanged; the forecast starts the month after forecast.asOf.
Show child attributesHide child attributes
asOfstringrequiredFirst day of the last month of history the model saw (yyyy-MM-dd). The forecast begins the following month.
cachedbooleanrequiredTrue when served from cache (same request, same data version).
confidenceenumrequiredSupport tier: high ≥ 100/month, medium ≥ 20/month, low below. Below 20/month the series is mostly noise and the band is wide; treat low as a shape, not a number.
highmediumlowhorizonintegerrequiredintervalenumrequiredmonthlymodelstringrequiredModel id that produced the quantiles.
pointsobject[]requiredShow child attributesHide child attributes
datestringrequiredFirst day of the forecast month, yyyy-MM-dd.
p10numberrequiredp50numberrequiredMedian forecast.
p90numberrequiredscenarioobject | nullrequiredThe resolved covariate path the forecast conditioned on, one value per horizon month. null when the rate series was unavailable and the forecast ran without it.
Show child attributesHide child attributes
rate30ynumber[]requiredsegmentsobject[]Per-segment forecasts when the request carried segment, one per label (top 12 by history total). Independent forecasts — they are not reconciled to sum to the total.
Show child attributesHide child attributes
confidenceenumrequiredSupport tier: high ≥ 100/month, medium ≥ 20/month, low below. Below 20/month the series is mostly noise and the band is wide; treat low as a shape, not a number.
highmediumlowlabelstringrequiredSegment label, never blank. Documents the dimension could not bucket are reported on the time-series history as its (unknown) segment; that disclosure is not a category and is not forecast.
pointsobject[]requiredsupportnumberrequiredMean monthly value of the forecast target over the last 12 months of history the model saw. The number behind confidence.
supportnumberrequiredMean monthly value of the forecast target over the last 12 months of history the model saw. The number behind confidence.
trimmedMonthsintegerrequiredTrailing months dropped from history before forecasting because they are still filling in (ingest lag on application months; closing lag on originated measures).
measurestringrequiredEcho of the measure measureValue reports, so a caller never has to infer which metric it is plotting.
previousobject[] | nullrequiredShow child attributesHide child attributes
completebooleanWhether this bucket's whole period is backed by data. false means the bucket extends past completeness.through, so it is built from a partial period and MUST NOT be compared against its neighbours or the same bucket a year earlier. Absent whenever completeness itself is absent; the two are emitted together or not at all.
datestringrequiredexcludednumberHow many of this bucket's documents the requested measure's sentinel guard excluded — documents carrying the field whose value is an out-of-range fill. Compare against units to see the share the value was computed over. Present per BUCKET because exclusion is not uniform over time: one period can be almost entirely fill values while its neighbors are clean, and a single response-level total would hide exactly that. Absent for units, which is a document count and cannot be guarded.
measureValuenumber | nullrequiredThis bucket's value for the requested measure (volume when none was supplied). Null when the bucket has no in-bounds document for the measure's field — sentinel-filtered rows do not contribute, so an empty bucket reports null rather than 0.
segmentsobject[]Show child attributesHide child attributes
labelstringrequiredmeasureValuenumber | nullrequiredThis segment's value for the requested measure. Null when the segment has no in-bounds document for the measure's field.
unattributedenumPresent and true on at most one segment PER DATE BUCKET, which is not a real category: it collects the documents that bucket could not attribute to any value of the requested segment, and its label ("(unknown)") is prose, not an identifier. Filter on THIS field, never on the label — a consumer joining a segment label to a real code must drop it. It is always the LAST entry of its bucket's segments, appended after ranking rather than placed by value, so it is the one segment that does not obey the ordering measure describes. It exists so a period's segments account for the same documents that period's own units counts: a document whose segment field holds no indexed term is absent from a terms breakdown entirely rather than forming a small segment, so without it a stacked series silently omits part of every bar. That reconciliation is exact for units; on an average it is not, because segments under the five-document floor are dropped and a segment field with more than 200 distinct values still truncates — neither loss is collected here. Reported per bucket rather than once per response because what cannot be attributed is not uniform over time. Absent when there is nothing unattributed, never false and never a zero-valued segment.
trueunitsnumberrequiredvolumenumberrequiredunitsnumberrequiredNumber of loans
volumenumberrequiredTotal loan volume in dollars
400objectValidation error. With `forecast`, `code` says which rule tripped: non-monthly interval, an average measure, or under 24 months of history.401objectUnauthorized403objectForbidden (authenticated, but missing required context — e.g. no active organization)404objectNot found413objectResponse payload too large — detail endpoint capped to fit Lambda response limits503objectOnly with `forecast`: the forecast service is unreachable or not configured for this stage. The history itself is fine — retry without `forecast` for an immediate answer. Also returned as `SearchUnavailable` (`error`: `search_timeout` / `search_overloaded`) when the search ran out of time or the cluster shed it.