Track Brazil Earnings Season with the CVM Filings API

A B3 earnings season packs dozens of Brazilian listed companies into the same few weeks. Each one drops an ITR (the quarterly filing), usually an investor presentation, and sometimes material facts with guidance or dividends. If you are looking for a Brazil earnings season API, this is the workflow: follow all of it through apicvm instead of refreshing the CVM portal by hand.

The problem

During earnings season you care about three questions: did the company report, where is the document, and what changed since my last run. The CVM portal answers them one company at a time, manually. Earnings calendars tell you when a company plans to report but don't hand you the filing itself. Scraping the portal is fragile and doesn't scale past a handful of tickers.

What gets published in a Brazilian earnings season

Brazil's regulator is the CVM. A quarterly season on B3 produces three document streams:

  • ITR — Informações Trimestrais, the quarterly financial statements (Brazilian quarterly filings — not an income tax return). Companies file within roughly 45 days of quarter end, so Q3 reports cluster around mid-November.
  • Investor presentations — earnings decks and institutional presentations from the IPE feed (APRESENTACAO_INVESTIDORES).
  • Material facts — fatos relevantes (FATO_RELEVANTE): guidance updates, buybacks, and shareholder remuneration announced alongside results.

The annual season adds the DFP, the standardized annual statements. For definitions, see the filing-type pages for ITR and DFP, plus What is a fato relevante?.

How apicvm helps

apicvm is a product API over CVM filings. The earnings-season workflow is four calls:

  1. Resolve each watchlist company — GET /v1/companies/resolve
  2. List season documents — GET /v1/documents with types, year, and date filters
  3. Download the original PDF — GET /v1/documents/:id/file
  4. Optional (Pro): page-level markdown extraction — POST /v1/document-text-extractions

Auth: Authorization: Bearer or X-API-Key. No key yet? The scoped demo API covers VALE3 without signup.

Setup

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

Step 1: Resolve the watchlist

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/companies/resolve?query=PETR4&by=ticker"

Confirm id, cnpj, and tickers[] for each company. Name searches that match more than one issuer return 409 AMBIGUOUS_RESULT with candidates — pin them down with by=ticker or by=cnpj.

Step 2: List the season's documents

Combine the three season types in one call with types=, scope to the year, and sort by reference date. perPage maxes out at 50.

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=VALE3&types=ITR,APRESENTACAO_INVESTIDORES,FATO_RELEVANTE&year=2026&perPage=50&field=dateRef&order=desc"

For VALE3 in 2026 this returns the season trail: the Desempenho_da_Vale_no_2T26 earnings presentation (dateRef 2026-07-31), the Q2 ITR bundle (dateRef 2026-06-30), and the material facts published around results. Each data[] item carries a document id (UUID), type, dateRef, year, name, and the nested company with tickers.

One nuance: for ITR and DFP bundles, dateRef is the period reference date (quarter or fiscal year end), not the day the filing hit the portal. For IPE-feed types like presentations and material facts, dateRef tracks the publication date. Sort descending and diff against your last run to catch what is new.

Step 3: Poll by date for new releases

To see what a company published on a specific day, filter by dateRef:

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=VALE3&type=APRESENTACAO_INVESTIDORES&dateRef=2026-07-31"

On 2026-07-31 that query returns exactly one document — Vale's 2Q26 performance deck. Run it daily per ticker during the season and you have an earnings tracker.

Step 4: Download or extract

curl -OJ -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents/<document-id>/file"

Downloads do not consume extraction credits. If you need the text — say, to feed an LLM summarizer for every deck in the season — enqueue POST /v1/document-text-extractions on Pro. Extraction is asynchronous: page-level markdown arrives via HTTPS callbacks, debited per page from your credits. Details in Extract text from CVM PDFs.

Example: Python watchlist

import os
import requests

BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
SEASON_TYPES = "ITR,APRESENTACAO_INVESTIDORES,FATO_RELEVANTE"

def season_documents(ticker: str, year: int):
    docs, page = [], 1
    while True:
        r = requests.get(
            f"{BASE}/v1/documents",
            params={
                "ticker": ticker,
                "types": SEASON_TYPES,
                "year": year,
                "perPage": 50,
                "page": page,
                "field": "dateRef",
                "order": "desc",
            },
            headers=H,
            timeout=60,
        )
        r.raise_for_status()
        payload = r.json()
        docs.extend(payload["data"])
        if page >= payload["meta"]["lastPage"]:
            return docs
        page += 1

for ticker in ["PETR4", "VALE3", "ITUB4"]:
    for doc in season_documents(ticker, 2026):
        print(ticker, doc["dateRef"], doc["type"], doc.get("name"))

Persist the UUIDs you have already seen; anything new on the next run is a season event worth alerting on. To run this on a schedule without your own infra, see Monitor Brazil CVM filings with GitHub Actions.

What the API is not

  • Not a forward earnings calendar. Reporting dates announced by companies are not in the corpus; you track documents once published.
  • Not real-time. Ingestion runs on a schedule, so a filing can appear after it hits the CVM. There is no push feed — poll GET /v1/documents.
  • Not quotes. Prices and market data are a different layer; see Brazil financial data API.
  • Coverage depends on the ingested corpus. An empty data array can be a gap, not proof that nothing was filed.
  • perPage caps at 50; paginate with page for heavy reporters.

Next steps

Ready to integrate?

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