Brazil Income Statement Disclosures API: Track DRE, Margins, and Non-Recurring Items from CVM Filings

A Brazil income statement disclosures API in the equity-research sense is not a live consensus EPS feed, a sell-side model host, or an engine that auto-builds adjusted EBITDA bridges. It is access to the CVM filings where Brazilian issuers publish the income statement (demonstração do resultado, DRE), gross and operating margin detail in explanatory notes, segment P&L when disclosed, and non-recurring or fair-value items that move reported net income — primary statements in DFP and ITR (Informações Trimestrais, not US income tax returns), performance narrative in FRE, and event PDFs when guidance or classifications change outside the normal calendar. apicvm lets you list those rows by ticker, download the original filing, and diff new document.id values on a watchlist during 3Q ITR season.

This guide shows which type values to query, annex filters for income-statement PDFs, and how this hub differs from revenue recognition, cash flow, and generic financial statements access.

The problem

Income-statement surveillance splits into three stacks that English search results often merge:

  1. Market data terminals — show price, consensus EPS, and vendor-calculated margins. They rarely store the issuer’s regulatory PDF with the full DRE, tax lines, and footnotes on one-offs or fair-value adjustments.
  2. Periodic packages — DFP, ITR, and FRE with revenue, cost of sales, operating profit, financial result, and net income lines plus explanatory notes. Essential during earnings season, but you still need ticker-first access and stable file IDs.
  3. Event disclosures — fatos relevantes and investor presentations when management revises volume, margin, or net-income guidance.

Scraping the CVM portal works for one ticker and breaks on a diversified watchlist. Bulk open-data ZIPs are dataset-oriented, not ticker-first. You want GET /v1/documents with stable document.id, then GET /v1/documents/:id/file for the original PDF — scoped to income statement workflows.

For segment mix and geographic splits, cross-check Brazil segment reporting disclosures API. For impairments and write-downs below operating profit, see Brazil asset impairment write-down disclosures API. This guide focuses on the API list-and-download pattern for DRE and related annexes.

Which filing type carries income statement detail?

Brazilian issuers do not expose a dedicated type=INCOME_STATEMENT in the apicvm document list. Detail usually appears under:

type Role in income statement workflows
ITR / DFP Periodic financials — DRE, EPS notes, tax expense, other comprehensive income references
FRE Annual reference form — business performance, margin drivers, and risk factors tied to earnings
FATO_RELEVANTE Material fact when guidance, reclassifications, or large one-offs affect reported profit
COMUNICADO_AO_MERCADO Occasional market communication on earnings pre-announcements
APRESENTACAO_INVESTIDORES Slides with adjusted EBITDA bridges (narrative; still a CVM filing row)

Practical rule: list latest ITR/DFP for each ticker during 3Q ITR season, filter annex rows whose name mentions resultado / DRE / income / demonstração, poll FATO_RELEVANTE for guidance keywords, and pull FRE once per year for structural margin context. After download, search PDF text for demonstração do resultado, DRE, receita, lucro, EBITDA, resultado financeiro, imposto, lucro líquido, EPS, ajuste, or não recorrente.

Issuer packaging varies: some filers embed the DRE inside a single financial-statements PDF; others split balance sheet, income statement, and cash flow into separate annex rows. Zero rows with a name filter does not mean the issuer omitted a DRE — broaden the list before download.

How apicvm helps

  1. Resolve the issuer — GET /v1/companies/resolve
  2. List periodic packages — GET /v1/documents with type=ITR or type=DFP and year
  3. Narrow to income-statement annexes — name tokens such as Resultado, DRE, or Income
  4. Optional section prefixes — GET /v1/document-prefixes when you need a named slice inside a large PDF (filter by section name)
  5. List event filings — GET /v1/documents with type=FATO_RELEVANTE or APRESENTACAO_INVESTIDORES
  6. Scope with dateRef; sort with field=dateRef&order=desc
  7. Download the PDF — GET /v1/documents/:id/file (no extraction credits)
  8. Optional (Pro): page-level markdown — POST /v1/document-text-extractions with async callback

Auth: Authorization: Bearer or X-API-Key. Try VALE3 without a key via the demo API.

Setup

export APICVM_KEY='apicvm_...'
export APICVM_URL='https://apicvm.dev'

Step 1: List quarterly filings for an earnings-season ticker

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=RADL3&type=ITR&year=2025&perPage=10&field=dateRef&order=desc"

Response rows include stable id, dateRef, name, and nested company metadata. Use id as your cache key — not name, which can be long and encoding-sensitive.

Paginate with page= when meta.lastPage > 1. perPage maxes at 50.

Step 2: Filter annex rows that likely contain the DRE

curl -s -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=RADL3&type=ITR&year=2025&perPage=50&name=Resultado" \
  | jq '.data[] | {id, type, dateRef, name}'

If that returns few rows, retry with name=Demonstra or list without name and inspect titles manually.

Step 4: Download the filing PDF

DOC_ID=123456
curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents/$DOC_ID/file" -o income-statement.pdf

Store document.id in your warehouse. Re-download when the issuer replaces a filing; do not assume name alone is a stable key.

Step 5: Watchlist poll (Python sketch)

import os, re, requests

BASE = os.environ["APICVM_URL"]
KEY = os.environ["APICVM_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
WATCH = ["PETR4", "VALE3", "RADL3", "WEGE3"]
IS_RE = re.compile(
    r"lucro|resultado|guidance|proje|ebitda|receita|margem|preju|"
    r"demonstra|dre|ajuste|recorrente|impairment|write.?down",
    re.I,
)
seen = set()

def list_events(ticker):
    r = requests.get(
        f"{BASE}/v1/documents",
        headers=HEADERS,
        params={
            "ticker": ticker,
            "types": "FATO_RELEVANTE,COMUNICADO_AO_MERCADO,APRESENTACAO_INVESTIDORES",
            "year": 2025,
            "perPage": 50,
            "field": "dateRef",
            "order": "desc",
        },
        timeout=60,
    )
    r.raise_for_status()
    return r.json().get("data") or []

for ticker in WATCH:
    for doc in list_events(ticker):
        if doc["id"] in seen:
            continue
        if not IS_RE.search(doc.get("name") or ""):
            continue
        seen.add(doc["id"])
        print(f"IS {ticker} {doc['dateRef']} {doc['name'][:70]}")

Wire this into GitHub Actions CVM filings monitor or extend the diff pattern from Brazil material facts monitoring API. For NLP over downloaded PDFs, see extract text from CVM PDFs for AI agents.

Where the income statement sits in the filings stack

Layer Types Income statement relevance
Periodic ITR, DFP DRE, tax, EPS notes, other comprehensive income references
Reference FRE Margin drivers, competitive context, earnings risks
Events FATO_RELEVANTE, COMUNICADO_AO_MERCADO Guidance changes, reclassifications, large one-offs
Investor materials APRESENTACAO_INVESTIDORES Adjusted metrics narrative (still download via API)

Brazil regulatory filings API explains the full layer map. Pair DRE pulls with quarterly ITR monitoring during 3Q ITR season (typically Oct–Nov). When revenue timing drives margin swings, cross-check Brazil revenue recognition disclosures API. When net income and cash diverge, see Brazil cash flow statement disclosures API. For the broader Brazil financial data API pillar, treat the income statement as one statement cluster inside periodic filings.

Current limitations

  • Documents, not parsed earnings engines — apicvm does not return revenue, gross margin, operating profit, or EPS parsed from tables or compute adjusted earnings.
  • Annex naming varies — name filters are heuristic; some DRE PDFs share a generic financial-statements title.
  • Polling, not push — no webhook when CVM publishes a new fact. Schedule polls and diff document.id.
  • Ingestion lag — sync is not real-time. A notice may appear on the portal before it is in the corpus.
  • Corpus coverage — not every issuer or period is present. Validate against the portal for production compliance use cases.
  • Demo scope — /v1/demo/* is limited to VALE3. Other tickers need a production key.
  • ITR disambiguation — Informações Trimestrais (CVM quarterly financials), not US income tax return software.

Next steps

Ready to integrate?

Get an API key and start querying Brazilian CVM filings programmatically.