Skip to main content
Parameters, response columns and types are generated from the SQL catalog and render under Endpoints → Panel in the sidebar. This page carries what a schema cannot: the conventions, the nulls that are deliberate, and the traps.

Overview

panel returns one row per observation, (id, date, metric, value), so B3 prices and fund fundamentals for the same window come in one request. Pivot locally; there is no server-side corr, rank or regression.
The grain is (id, asset_class, date, metric). 385 CNPJs file under two families in the same month, and the panel returns one row per family. Pivoting on (id, date, metric) alone raises on the duplicate or silently averages two vehicles. Pass p_entity_type, or keep asset_class in your pivot key.
Over 1,000 rows the panel refuses; it never trims. A window over one page raises 22023 (HTTP 400): page with p_after, or narrow the request. See Paging.

Parameters

Universe mode

Leave p_ids empty and name a family with p_entity_type: the panel selects that family’s funds itself, optionally floored by p_min_nav and p_min_months. Nothing is ranked server-side. Signed-in callers only (each page re-scans the family’s whole window); catalog().limits.tiers.<tier>.panel_universe says which you are.

Metrics

A metric asked outside its asset classes (catalog().applicability) gives no rows for those ids, not nulls or zeros. FIDC delinquency starts in 2013-01 and is on every row from 2020-11; before that a fund with no tab VI row is null, not zero (catalog().regime_breaks).
freq=day is quotes only. No CVM fundamental is daily, so nav with p_freq: "day" returns the quote rows and nothing else. Mix asset classes at freq=month, where the B3 value is the last real session in the month. Aligning a monthly NAV to a daily calendar would require filling, and this API does not fill.

Response fields

Rows are ordered by date, id, metric, asset_class.

Example

Paging

Send p_after: "" for the first page, then the last row’s key '<date>|<id>|<metric>|<asset_class>'. A full page always has a next page; a short page is always the last. The SDK does this: iter_panel(...) / panel_all(...). Range headers and limit/offset do not page an RPC call. For scale: 3 ids × 2 metrics × 5 years of daily quotes is ~7,500 rows, eight pages.

Notes

  • Nothing is forward-filled or interpolated. A month a fund did not file is absent. Correlate pairwise-complete.
  • Two shapes of “no data”. nav, quota, delinquency, yield, inflows, redemptions, quotaholders and close_return never appear with a null value; a gap is an absent row. close and volume are emitted every session and can carry a JSON null.
  • close_return is adjusted across a share-count event. Where a split, grouping or bonus (DESDOBRAMENTO, GRUPAMENTO, BONIFICACAO in B3’s corporate-event history) lies between the two prints, daily or monthly (monthly: anywhere between the two month-end prints), the previous close is divided by the event’s share ratio (1 + factor/100 for a split or bonus, the factor for a grouping) before the return is taken. A close of 100.00 before a 1:4 split is 25.00, so a 26.00 close is +4%, not −74%. An event with an unreadable factor, or published twice with two factors, leaves the row absent. Dividends and JCP still move it, it is not a total return, and an event the nightly sweep has not stored yet is not seen, so treat a jump over ~40% as suspect until you have checked.
  • close_return needs a predecessor. Monthly: only when the preceding row is the immediately preceding calendar month. Daily: against the previous stored session, so a session missing from the warehouse makes the return span the gap (check coverage). The first observation in a window is always absent, so request more history than you analyze.
  • Windows differ per side. Quote metrics honor p_from exactly; fund metrics start from date_trunc('month', p_from) and p_to is month-truncated too, so p_to of 2026-07-01 still returns all of July for a FIDC filed at 2026-07-31.
  • Derivatives carry no close_return, and their real grain is wider (COTAHIST keys them on board, termo also on term), so a within-session tie is cut deterministically (shortest term wins), not averaged. For the full grain use option_history or termo_history. There is no underlying column anywhere.
  • Every cash-market BDI board is accepted; one row is kept deterministically when a ticker has multiple boards in a session.
  • Statement timeout: a call that runs too long fails outright rather than returning part of a panel.
  • An empty array means no observation matched: unknown ids, no filings in the window, a metric that does not apply, or an ignored metric name. Confirm with lookup and coverage.