Sign up

Products

Status

Research Datasets

Direct, row-level access to the licensed multi-decade research archives behind the API (fundamentals, estimates, credit, options, governance, ownership, and factor returns), plus the derived feature panels the platform computes for its own models. Where the product endpoints give you a curated answer, these give you the underlying table.

What's inside

Two families of routes:

MethodEndpointPlan / creditsMCP toolDescription
GET/api/v2/datasetsStarter+ / 4 credits (funds)research_datasetsList every servable licensed dataset slug. No parameters.
GET/api/v2/datasets/{dataset}Varies by dataset, see belowresearch_readRead rows from one licensed dataset. ticker (string, optional): on most datasets, an exact filter on the dataset's own symbol column, when it has one; financial_ratios and implied_vol_by_ticker resolve the symbol before reading (see below). limit (integer, 1 to 50000, default 1000). Reads without ticker are capped at 5,000 rows.
GET/api/v3/features/datasetsStarter+ / 3 (quant_signals)features_catalogueThe feature-store catalogue: every derived panel with measured coverage and freshness. No parameters.
GET/api/v3/features/{dataset}Starter+ / 3 (quant_signals)features_datasetRead one derived panel: one symbol's time series, or the latest cross-section. ticker (string, optional). limit (integer, 1 to 5000, default 500). since, until (YYYY-MM-DD, optional, inclusive).

The licensed datasets take only ticker and limit. There are no dataset-specific filters: to narrow a table further, filter the rows you receive.

Every licensed-dataset response carries a note describing that dataset's coverage, keying and any quirks. Read it before building against a dataset.

JSON
{  "ok": true,  "timestamp": "...",  "dataset": "zacks_consensus",  "n": 1,  "rows": [ ... ],  "source": "...",  "note": "Daily sell-side EPS consensus (mean/std/count by reference period), 2.9M rows 2024-08 → present, ~5-week lag."}

Access & cost

Listing the licensed catalogue requires Starter+ and costs 4 credits under funds. The feature-store routes bill as quant_signals: Starter+, 3 credits per call.

Each licensed dataset bills at the credit cost of the product group it belongs to, and is gated by that group's plan. The groups are:

Billed asPlanCreditsDatasets
fundsStarter+4Every dataset not listed below
news_sentimentStarter+2zacks_consensus, zacks_surprises
alt_dataPro+3boardex_profile, boardex_composition, boardex_networks, audit_fees, audit_restatements, auditor_changes
events_transcriptsPro+3ciq_keydev, ciq_transcripts
creditPro+4markit_cds, cds_composites, markit_credit_indices, ciq_ratings, dealscan_facility, dealscan_pricing, trace
options_flowPro+4markit_short

The cost of each call is reported in the X-Credits-Cost response header. Read it rather than assuming. Failed requests, including an unknown slug (404), are not billed.

Recently added

zacks_consensus: Starter+ · 2 credits. Daily sell-side EPS consensus (mean / std / count by reference period), 2.9M rows, 2024-08 to present, ~5-week lag. Columns include ticker, est_type, reference_period, observation_date, est_mean, est_std, number_of_est.

zacks_surprises: Starter+ · 2 credits. Quarterly EPS actual-vs-consensus surprises (68.7k rows) with report dates. Columns include ticker, report_date, reference_period, actual_eps, consensus_eps, surprise_pct, number_of_est.

Note:

Not every surprise row has a consensus: consensus_eps and surprise_pct are null where no estimate existed (number_of_est: 0). Filter on number_of_est > 0 when computing surprise statistics.

markit_credit_indices: Pro+ · 4 credits. CDX + iTraxx (EU / Asia / SovX) daily composite spreads and prices by series / version / tenor, 2018 to T-2, 3.8M rows. Index-keyed (indexfamily, indexticker): there is no equity ticker column. For the curated view with on-the-run filtering, use /api/v3/credit/indices instead.

boardex_networks: Pro+ · 3 credits. Director interlock edges (which boards share directors), 5.0M rows, weekly refresh. Keyed by boardid pairs; resolve ids via boardex_profile. Columns include associationtype, boardname, companyname, directorname, overlapyearstart, overlapyearend, role.

Governance archives now refresh weekly

boardex_profile and boardex_composition were repointed on 2026-08-01 from a frozen 2026-03 archive to a weekly-refreshing pull. Columns now follow the licensed-research-native shape rather than the previous normalized one. If you built against the old column names, re-read the note and adjust. boardex_composition carries role spells keyed by boardid / directorid; resolve both via boardex_profile.

The licensed catalogue

GET /api/v2/datasets returns the servable slugs in datasets and their number in count. That response is authoritative, and an unknown slug returns 404. The table below is a guide to what the slugs hold and how ?ticker= behaves on each; if it and your listing ever disagree, trust the listing.

On most datasets ?ticker= is an exact match on the dataset's own symbol column. On a dataset keyed by an internal id instead, the response states that ticker was ignored. Two slugs work differently: implied_vol_by_ticker (below) and financial_ratios.

financial_ratios resolves ?ticker= to one security through the shared security resolver before reading, because symbols in this 1970 to 2025 archive were reused by different companies. It keys on the security's 8-character CUSIP and falls back to the symbol column, and the response carries an identity block (resolved_symbol, company_name, keyed_on, key_confidence) with identity_verified. A symbol that does not resolve returns no rows and error: "unresolved_symbol:<status>" (for example unresolved_symbol:ambiguous) rather than a guess; a resolved security with no rows returns warning: "no_rows_for_security".

Two neutral slugs are accepted alongside the archive names, and the listing may show the archive name instead:

  • cds_composites: the full 2005 to 2025 single-name CDS composite spread history. It reads the same table as markit_cds and bills the same (credit, Pro+, 4 credits).
  • implied_vol_by_ticker: symbol access to the daily implied-volatility aggregates, which are keyed by an internal id; the same data as optionmetrics_by_ticker. It requires ?ticker=, resolves the symbol to that id, and filters on it. Without ticker the response carries error: "ticker_required" and no rows.
CategorySlugs?ticker= matches
Equity pricescrsp_monthly, crsp_daily, crsp_delisting, crsp_distributionsThe symbol on crsp_monthly; the others are keyed by an internal security id
Mutual fundsmutual_fund_holdings, mutual_fund_returnsThe held security's symbol on mutual_fund_holdings; mutual_fund_returns is keyed by fund id
Fundamentalscompustat_annual, compustat_quarterly, compustat_segments, segment_customers, supply_chain_links, financial_ratiosThe symbol on annual and quarterly; the supplier's symbol on supply_chain_links; segments and customers are keyed by gvkey; financial_ratios resolves the symbol to a security (see above)
Analyst estimatesibes_summary, ibes_detail, ibes_actuals, ibes_guidance, ibes_ptg, ibes_recommendationsThe official symbol on summary, detail, price targets and recommendations; the estimate-feed ticker (usually, not always, the symbol) on actuals and guidance
Implied volatilityoptionmetrics_daily, optionmetrics_volsurface, implied_vol_by_ticker (also served as optionmetrics_by_ticker)Keyed by an internal id; use implied_vol_by_ticker for symbol access
Securities financemarkit_cds (also cds_composites), markit_shortThe symbol on markit_cds; markit_short is keyed by gvkey / security id
Credit and loanstrace, markit_credit_indices, dealscan_facility, dealscan_pricing, ciq_ratingsThe borrower symbol on dealscan_facility, where available; trace is keyed by bond id, markit_credit_indices by index, the others by internal ids
Transcripts, ratings and key developmentsciq_transcripts, ciq_keydevKeyed by company id. ciq_transcripts holds metadata only; full text is served by /api/v3/transcripts/*
Governance and compensationboardex_profile, boardex_composition, boardex_networks, execucompThe symbol on boardex_profile and execucomp; composition and networks are keyed by board and director ids
Forensic auditaudit_fees, audit_restatements, auditor_changesKeyed by company / CIK inside the row
ESG and crowd estimatesmsci_esg, estimize_consensus, estimize_estimatesThe issuer symbol on msci_esg; the symbol on both estimize datasets
Estimates, consensus feedzacks_consensus, zacks_surprisesThe symbol
Factorsfama_french_daily, fama_french_monthlyMarket-level series, no ticker

Known limits of these archives (read before a backtest). Values match the vendors'; the gaps are in coverage and in the knowledge dates, and they are being restated.

  • crsp_daily: from 2000 to 2024 it holds common stocks only (about 60% of the vendor's rows; ETFs, ADRs and other share classes are missing there), and rows before 2000 have null cfacpr and cfacshr. Its knowledge dates are not usable as point-in-time clocks.
  • crsp_delisting, crsp_monthly (2026 rows): knowledge dates follow the vendor's release rule (month end plus 42 to 49 days), not the date Wealthnow first held the row.
  • crsp_distributions: the legacy archive, last updated 2024-12-31; later distributions are not in it.
  • ibes_actuals, ibes_recommendations: knowledge dates are the announcement date on recent rows and empty on older rows, so they can precede when the data was available. A few thousand recent vendor rows are missing and a few hundred values have since been revised.
  • markit_credit_indices: see Credit; each composite is stamped at 00:00 UTC on its trade date, before that day's composite exists.

Feature store

The feature store serves the derived research panels the platform computes for its own models: price, return and liquidity features, monthly fundamentals, analyst-estimate dynamics, options and volatility-surface features, insider and institutional-ownership features, news-sentiment features, betas, and regime and macro features. Slugs are product names, not table names.

Call the catalogue first. GET /api/v3/features/datasets is the only place the slugs are published. Measured live on 2026-08-02 it listed 19 servable datasets totalling 17,062,613 rows, plus 5 withheld and 2 excluded. How many are current or archival changes with the data, so read coverage.datasets_current, coverage.datasets_archival and coverage.datasets_withheld in the response. Each entry carries:

  • dataset, title, summary, grain (daily, weekly, monthly or quarterly), market_wide, symbol_addressable, feature_columns and path. A panel that carries a per-row vintage also has vintage_column, with its name and meaning.
  • coverage: measured rows_total, symbols_total, observation_dates, history_first and history_last, counted over observations only. rows_dated_after_today counts rows stamped with a date that has not happened yet. On a monthly panel, rows_written_before_month_end counts rows dated on or before today that were written no later than the month end they are stamped with, such as a month in progress; it is null on other grains. Neither kind of row is served.
  • freshness: status is current only when both clocks agree: the producer is inside twice its own declared cadence, and the data is on its own rhythm. Otherwise a genuine historical panel is archival: still readable, and every read of it says so. advisory states the result in one sentence.

How the data clock is read. stale_for_its_own_cadence is true when the newest observation (data_through) is more than three of the table's own typical gaps between observations old, so a panel rewritten nightly whose data still ends months ago is not current. A daily panel is counted in weekdays, so a weekend is not a missed observation: data_clock_counted_in is business_days, with data_lag_business_days and typical_gap_business_days beside the calendar-day data_lag_days and typical_gap_days. Other grains are counted in calendar_days. A panel with a vintage clock is graded on it too: vintage_clock gives its column, through (the newest vintage), lag_days, typical_gap_days and stale, and a stale vintage makes the dataset stale.

not_current_reason says which clock is behind:

not_current_reasonstatusMeaning
no_scheduled_producerarchivalA fixed historical archive with no producer.
producer_behindarchivalThe producer has not written within twice its cadence.
data_behind_its_own_cadencearchivalThe producer is on schedule, but the data it writes is behind its own rhythm.
producer_stopped_and_not_a_panelwithheldThe producer has stopped, and the dataset has no history to fall back on.
data_behind_and_not_a_panelwithheldThe data is behind its own rhythm, and the dataset has no history to fall back on.

The catalogue also lists withheld datasets (the producer has stopped and there is no history to fall back on; they have no route) and excluded ones (live but not sold here), each with the measurement behind the verdict. A servable dataset can also be measured into withheld: its catalogue entry then shows status: "withheld" with its not_current_reason, it is counted in datasets_withheld rather than datasets_servable, and reading it returns 404 with error: "dataset_withheld", not billed, until it recovers.

Reading a panel. With ?ticker=, /api/v3/features/{dataset} returns that symbol's observations, newest first. Without it, it returns the latest cross-section: every symbol on the most recent observation date. since and until bound the window.

  • observation_date is the date the row describes. since, until and the latest cross-section all key on it.
  • A panel that carries a vintage serves it as its own column beside observation_date, never in its place. On equity_fundamental_features_monthly, ratio_vintage is the publication date of the valuation and profitability ratios on the row; a vintage is carried forward to later months until a newer one is published. On beta_features, returns_data_through is the last month of the return history the beta was estimated on: a security whose returns stopped keeps its last estimate, so a row dated today can carry one from decades earlier.
  • A row is not served until it is an observation. A row dated after today is not one yet, and neither is a monthly row written on or before the month end it is stamped with, such as the month in progress on equity_returns_monthly. coverage counts both kinds.
  • The symbol is resolved to one security first. An ambiguous, historical (renamed or delisted) or unknown symbol is refused, never guessed, and identity.identity_verified states whether the read was keyed on an authoritative identifier or on the resolved security's symbol.
  • When a symbol has been carried by more than one company and the panel is read by symbol, the series is bounded to the period the current company can have held it, when an earlier holder's end date is known, and window.since_applied is symbol_reuse_floor. When a reused symbol's series is not bounded this way, the rows are still returned, identity.identity_verified is false, and result is rows_may_blend_issuers. identity.symbol_reuse.prior_holders_of_symbol lists the earlier holders.
  • Market-wide datasets have one row per date, and a panel keyed by a non-symbol id cannot be read by symbol: passing ticker to either returns 422 with error_code: "symbol_not_supported".
  • Every read carries the dataset's coverage (with rows_returned and truncated) and freshness, so an empty rows array arrives beside the count of symbols that do have rows. result is the machine-readable outcome:
resultMeaning
rowsRows returned.
rows_may_blend_issuersRows returned, but the symbol was reused by more than one company and the series could not be bounded, so rows from an earlier issuer may be mixed in. Do not join the panel on it without checking identity.symbol_reuse.
no_rows_for_symbolThe symbol resolved, but the dataset has no observations for it in the window.
no_rows_in_windowA cross-section read found no observations in the window.
symbol_ambiguous, symbol_historical, symbol_unknownThe symbol was refused: shared by several current securities, only matched a renamed or delisted security, or is not known. No rows.
symbol_unavailableThe resolver could not run, so the symbol was not checked. No rows; retry later.
symbol_not_keyableThe symbol resolved, but the security carries none of the identifiers this panel is keyed by. No rows.

All of these arrive with HTTP 200.

  • An unknown or withheld slug returns 404, including a servable dataset measured into withheld (error: "dataset_withheld"), and an unreadable store returns 503; neither is billed.

Servable slugs at the time of writing (the catalogue is authoritative):

AreaSlugs
Price, return and liquidityequity_price_features_daily, equity_returns_monthly
Fundamentals and accountingequity_fundamental_features_monthly, forensic_accounting_features
Analyst estimates and actionsanalyst_estimate_features, analyst_action_signals
Options and volatilityimplied_vol_features_monthly, options_positioning_signals, options_surface_features, vol_term_structure_features
Ownership and flowinsider_activity_features, institutional_ownership_features, legislative_and_fund_flow_signals
Sentimentnews_sentiment_features
Riskbeta_features
Market-wide regime and macroequity_regime_features, macro_regime_features, macro_features, futures_curve_features

Examples

List every licensed dataset (4 credits)

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v2/datasets" | jq '.count, .datasets'
Note:

Listing requires Starter+ and costs 4 credits. Cache the slug list to avoid paying for it on every query.

Read EPS surprises for one ticker (2 credits)

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v2/datasets/zacks_surprises?ticker=AAPL&limit=8" \  | jq '.note, .rows[0]'

Without ticker, a read returns rows from across the whole table, capped at 5,000. For example, ?limit=5 without a ticker returned this first row:

JSON
{  "entry_date": "2026-06-29T00:00:00",  "report_date": "2026-06-29T00:00:00",  "ticker": "AIRT",  "reference_period": "2026-03-01T00:00:00",  "actual_eps": 28.75,  "consensus_eps": null,  "surprise_pct": null,  "number_of_est": 0}

Read implied volatility by symbol (4 credits)

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v2/datasets/implied_vol_by_ticker?ticker=AAPL&limit=250"

Read director interlocks (3 credits, Pro and up)

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v2/datasets/boardex_networks?limit=5" | jq '.rows[0]'

Browse the feature store, then read one panel (3 credits each)

# 1. The catalogue: slugs, coverage, freshnesscurl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v3/features/datasets" \  | jq '.coverage, [.datasets[] | {dataset, grain, status: .freshness.status}]' # 2. One symbol's daily price features since Junecurl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v3/features/equity_price_features_daily?ticker=NVDA&since=2026-06-01&limit=100"

Notes for agents

  • Always read note on a licensed dataset, and freshness on a feature panel. Coverage windows, lags, row counts and keying differ per dataset and change as archives are repointed.
  • Column names are archive-native. The licensed tables are raw research tables. Expect lowercase concatenated names (indexfamily, overlapyearstart, number_of_est), not a normalized schema.
  • Not every dataset is ticker-keyed. markit_credit_indices is index-keyed; boardex_networks is board-id-keyed; several archives are keyed by internal security ids. Check the note before joining on ticker, and use Reference Data to translate identifiers.
  • Nulls are real. Research archives carry genuine gaps. A null means the source had no value, not that the API failed.

Next steps