Overview
From a ticker to a clean revenue series, stopping at the two places where a reasonable assumption produces a wrong answer that looks right.1. Resolve the company
tickers from CVM’s published FCA map. There is no derived ticker-to-CNPJ join anywhere — the mapping is either published or absent.
Both financial endpoints accept a ticker, a CNPJ or a CVM code as p_id.
2. Start with the summary
company_financials is the pre-computed headline: one row per filing.
revenue, gross_profit, net_income, total_assets, equity, net_margin_pct and roe_pct, alongside doc_type, scope, ref_date, period_start, period_end, period_months, version, setor and segmento.
Banks file a different chart of accounts — but
3.11 is still net income. What differs is what each code means. For Banco do Brasil (cd_cvm 1023, FY2024 consolidated), 3.01 is Receitas de Intermediação Financeira rather than Receita de Venda de Bens e/ou Serviços, and 3.05 is already Resultado antes dos Tributos sobre o Lucro rather than EBIT. Net income is 3.11 just as it is for an industrial filer; 3.09 is profit before the statutory profit-sharing on 3.10, so the two agree only where 3.10 is zero — as it happens to be there.company_financials resolves net_income from the filed net-income label (catalog v36), so it lands on 3.11, 3.09 or 3.13 depending on the chart, and never substitutes one code for another. If you pull raw accounts in step 3, read the account_name filed alongside the code rather than assuming a code carries the same concept across charts, and use setor (on every row) as the partition key for any peer median or rank.3. The raw statements — and period_months
p_statement selects the statement group — DRE, BPA, BPP, and the others as filed. Omit it for all.
An ITR prints each account twice under one ref_date:
The rows differ only by their period span, which is why the span is published rather than collapsed — either choice is wrong for somebody.
Always filter on
period_months before aggregating.
4. Consolidated or individual
p_scope is con by default; ind is the parent company alone. For a group with subsidiaries they are different companies in every meaningful sense.
Do not compare across scopes, and do not switch scope mid-series — a break there looks exactly like a business event.
5. Restatements
A re-filed statement is submitted under a higherversao. Only the newest version of each statement is served, so you never see one quarter twice with two different numbers.
version is published anyway, so you can see a restatement happened. In company_financials, balance-sheet rows are joined on the same document version — a restatement never mixes old assets with new equity.
6. Comparatives are excluded
Each filing prints the prior-year figure beside the current one. The API serves only the period the document is for (CVM’sÚLTIMO), never the comparative (PENÚLTIMO). To read an earlier period, pull the earlier document.
7. Windows
financials refuses rather than truncates: a window over 1,000 rows raises 22023. It offers no cursor on purpose — a statement has tens of rows, so a window that wide is a mistake rather than a walk.
Narrow p_from/p_to, or pin p_statement. A full DRE for one company across five years is comfortable; every statement for five years is not.
Note: coverage() reports financials with a complete_through of null on purpose — the completeness model describes fund filing cadence and says nothing about companies.
Putting it on one axis
Once you have a clean series,panel aligns it with market data in the same long (id, date, metric, value) shape. See your first screen.
Next
Financials reference
Every column, every statement group.
Paging without losing rows
What to do when
financials refuses your window.