> ## Documentation Index
> Fetch the complete documentation index at: https://octo-98895abd.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Known limitations

> What this API does not do yet, written down before you hit it — sector charts of accounts, unresolvable tickers, duplicated ITR spans, unadjusted prices.

Every item below is measured, not suspected. Where something is planned it says
**planned** and says why it has not shipped; where the answer is "this cannot be
fixed", it says that instead. [Conventions & limits](/api-docs/conventions) is the
contract — caps, nulls, freshness, errors. This page is the list of places where the
contract is correct and still not enough.

<Note>
  Nothing here is a bug report. A limitation that would be fixed by fabricating a
  value — a guessed ticker↔CNPJ join, a derived split factor, an English label
  keyed on a code that means two things — stays a limitation on purpose.
</Note>

## Account codes are not comparable across sectors

CVM's chart of accounts is **sector-specific**. The same `account_code` carries a
different line in a bank's filing than in an industrial company's, and nothing in
the code itself tells you which chart you are reading. Measured against the live
API for PETR4 (industrial) and Banco do Brasil (`cd_cvm` 1023, bank):

| `account_code` | Industrial (PETR4) | Bank (Banco do Brasil) |
| - | - | - |
| `3.01` | Receita de Venda de Bens e/ou Serviços | Receitas de Intermediação Financeira |
| `3.03` | Resultado Bruto | Resultado Bruto de Intermediação Financeira |
| `3.05` | Resultado Antes do Resultado Financeiro e dos Tributos (EBIT) | Resultado antes dos Tributos sobre o Lucro |
| `3.07` | Resultado Antes dos Tributos sobre o Lucro | Lucro ou Prejuízo das Operações Continuadas |

<Warning>
  **Do not compare a ratio built on an account code across sectors.** `3.05` is
  operating profit before financial result for an industrial and pre-tax profit for
  a bank — two different levels of the income statement. A screen that ranks both on
  `3.05` is ranking two different quantities and will look plausible while doing it.
</Warning>

Four consequences, all visible in the response:

* **`setor` and `segmento` are on every `financials` and `company_financials` row.**
  They are there to be used as a partition key, not read as a label: partition every
  median, rank and percentile by `setor`, and the comparison above stops being a
  cross-chart one. This is what makes the limitation *navigable* — it does not remove it.
* **`api.financials` returns the as-filed Portuguese `account_name`.** It is the only
  label in the payload that is correct for every chart, because it is the one the
  company filed. Read it, not just the code.
* **There is deliberately no canonical English line-item mapping.** Keying one on
  `account_code` would mislabel one sector or the other — `3.03` cannot be both
  "gross profit" and "gross financial intermediation result" under one name.
* **Insurers and other regulated sectors are expected to differ too**, and have not
  been characterised. Treat "not a bank and not an industrial" as unknown rather
  than as one of the two columns above.

<Note>
  **Shipped (catalog v29).** `api.income_statements` returns the income statement as
  one row per period with named fields, and it resolves each field from the **as-filed
  label** rather than from the account code. `chart` names the layout the filing used
  (`industrial`, `bank`, `insurer`). `setor` and `segmento` also ride on every
  statement row (v28) for peer medians.

  Keying on the label turned out to be *more complete*, not just safer: net income
  sits on `3.11` for two charts, on `3.09` for a third that files no `3.11`, and on
  `3.13` for insurers. Since v36 `company_financials.net_income` is keyed the same
  way, so the two surfaces agree.

  **Shipped (catalog v35).** `api.balance_sheets` and `api.cash_flow_statements`
  follow the same design. On the balance sheet, equity sits on `2.03`, `2.07` or `2.08`
  depending on the chart, and where one label is filed twice (current and non-current
  `Empréstimos e Financiamentos`) the parent line's label tells them apart. Banks file
  no current/non-current split and no debt line, so those fields are null for them.
  The cash flow maps only the section totals and the cash reconciliation: capex and
  dividends are free text per filer, so read those lines with `financials`.

  **Still not offered.** A canonical English mapping for *every* line. The named field
  set above is a bounded, measured subset; a full mapping is not, and a code-keyed one
  would still mislabel a chart.

  **Planned, and deliberately behind it.** A friendlier `financials` output shape —
  readable period labels, scaled values, year-over-year change. It is deferred
  precisely because the sector separation has to land first: a convenient wide shape
  built on today's codes would harden the mistake above into an interface.
</Note>

## `net_income` is keyed on the filed label, never on a code

Since catalog v36, `api.company_financials` resolves `net_income` the same way as
`api.income_statements`: from the filed label `Lucro/Prejuízo Consolidado do
Período` (or `Lucro ou Prejuízo Líquido Consolidado do Período`), wherever the
chart puts it.

| Chart | Net income on | `3.11` is |
| - | - | - |
| industrial, bank A | `3.11` | net income |
| bank B | `3.09` | not filed |
| insurer | `3.13` | continuing operations |

Until v35 it read `3.11` alone. That returned `null` for the 282 bank-B statements
(Itaú Unibanco and BTG Pactual among them) and, for insurers, returned the
continuing-operations line under the name `net_income`.

No code is substituted for another. For Banco do Brasil, FY2024, consolidated:

| `account_code` | `account_name` | Value |
| - | - | - |
| `3.09` | Lucro ou Prejuízo antes das Participações e Contribuições Estatutárias | R\$ 29.17bn |
| `3.10` | Participações nos Lucros e Contribuições Estatutárias | R\$ 0.00 |
| `3.11` | Lucro ou Prejuízo Líquido Consolidado do Período | R\$ 29.17bn |

`3.09` is profit **before** statutory profit-sharing on this chart, and matches `3.11`
only because `3.10` is zero. A `COALESCE(3.11, 3.09)` would be wrong for the first
filer with a non-zero `3.10`; the label match never reads it.

This is verified for **one** bank. It is not a claim about every bank, and the
non-bank charts have not been swept for the same pattern.

## Not every listed company resolves from its ticker

A ticker resolves to a company only through CVM's published FCA
valores-mobiliários map, and that map covers only the companies that published it.
Nothing is name-matched — a guessed ticker↔CNPJ join is exactly what this API
refuses to make.

So a ticker can be real, traded, and still resolve to nothing. `ITUB4` does:

<CodeGroup>
  ```bash curl theme={null}
  curl -s -X POST "$SILO_URL/rpc/lookup" \
    -H "apikey: $SILO_ANON_KEY" -H "Content-Type: application/json" \
    -d '{"p_query":"ITUB4"}'
  # One row, and it is a ticker row:
  # [{"id":"ITUB4","id_type":"ticker", ...,"cnpj":null,"tickers":null}]
  # No cd_cvm row, so there is no company to read fundamentals for.

  curl -s -X POST "$SILO_URL/rpc/financials" \
    -H "apikey: $SILO_ANON_KEY" -H "Content-Type: application/json" \
    -d '{"p_id":"ITUB4","p_statement":"DRE"}'
  # 200 []
  ```

  ```python Python theme={null}
  silo.lookup("ITUB4")       # ticker row only: cnpj None, tickers None
  silo.financials("ITUB4")   # [] — nothing resolved, not an error
  ```
</CodeGroup>

The quote row exists, so the ticker is found; the company arm is empty, so
`financials` resolves nothing and returns `200 []`. An empty array here means
"unresolvable", not "this company filed nothing".

**Workaround:** resolve by company name or `cd_cvm` with `api.lookup`, then pass the
id it returns. A company row carries `cnpj` and a `tickers` array; those ids read
fundamentals reliably.

## A quarterly filing publishes every account twice

An ITR prints the same account under one `ref_date` twice — once for the three-month
span, once year-to-date — distinguished **only** by `period_start` / `period_end`,
surfaced as `period_months`. Nothing is collapsed for you, because collapsing means
choosing, and either choice is wrong for someone.

<Warning>
  Filter on `period_months` before you aggregate, chart or average anything. Adding a
  3-month row to a 6-month row double-counts the quarter, and the two rows are
  otherwise identical in every field you would normally group by.
</Warning>

And you cannot reliably rebuild a cumulative figure by summing quarters:

* A company with a **non-calendar fiscal year** breaks the arithmetic — São Martinho
  (`cd_cvm` 20516) files April–March, so its nine-month period starts 1 April, not
  1 January.
* A **restated earlier quarter** breaks it too; only the newest `version` of each
  statement is served, so the quarter you would subtract may no longer be the quarter
  that was originally filed.

## Quotes are unadjusted, except one column

`close`, `close_unit` and the `adjusted` flag are as traded, and `adjusted` is `false`
on every quote row: a statement of fact rather than a default waiting to be flipped.
A return computed from them across a split date is wrong, by the split ratio.

The one adjusted price is [`quote_history`](/api-docs/quotes)'s `close_adj`, its
default field (and, with cash reinvested, the selectable `close_total_return`). It is
continuous across splits, groupings and bonus shares, anchored to the ticker's latest
session, and a window SILO cannot stand behind is refused with the cause, never served
raw: outside shares and units, before the issuer's corporate events are proven swept,
or at an event this version does not adjust. `close_total_return` is NULL with a reason
where a distribution cannot be valued. Spin-offs, mergers, capital reductions and
subscriptions are not adjusted. `quotes`, the typed views and `panel` are unchanged.
Nothing is interpolated or forward-filled either; see
[Market coverage](/api-docs/market-coverage#what-is-not-here).

## The B3 lending and flow group is a ratchet

Roughly 21 business days of retention at the source, no archive, and no backfill at
any price. It affects `short_interest`, `short_interest_by_sector`, `investor_flow`,
`lending_trades` and `lending_participants`: a session not captured on the day is
gone, not expensive.

This is the one limitation on this page that no amount of work here can fix, and it
is documented in full — including the silently clamped HTTP 200 — under
[the B3 BDI ratchet](/api-docs/market-coverage#the-b3-bdi-ratchet). Read it before you
plan a long lending series.

## Next

<CardGroup cols={3}>
  <Card title="Market coverage" icon="calendar-range" href="/api-docs/market-coverage">
    How far back each domain goes, and the ratchet in full.
  </Card>

  <Card title="Conventions & limits" icon="ruler" href="/api-docs/conventions">
    The contract: caps, null semantics, freshness, errors.
  </Card>

  <Card title="Paging without losing rows" icon="list-ol" href="/api-docs/guides/pagination">
    Three ways a response gets cut, and only one tells you.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.