Brazil Public Company Data API for Research Pipelines

You run a research pipeline — equity models, sector screens, or internal dashboards — and need a Brazil public company data API that returns regulatory filings, not just price quotes. Market data vendors cover tickers and prices; they rarely give you programmatic access to CVM PDFs with stable metadata.

apicvm fills the regulatory layer: resolve B3 issuers, list DFP/ITR/FRE documents by year, download originals, and optionally extract page-level text for downstream NLP.

The persona

Typical users:

  • Quant researchers building Brazil factor models that need filing timestamps and document access
  • Data engineers wiring CVM documents into a warehouse alongside market data
  • Fintech teams shipping "view source filing" features for Brazilian equities

Common blocker: CVM open data is bulk CSV/ZIP — great for panels, awkward for "fetch VALE3's latest quarterly filing on demand."

The problem

Research pipelines need repeatable lookups:

  1. Ticker → company — canonical CNPJ and name
  2. Company → filings — filter by type (DFP, ITR, FRE) and year
  3. Filing → file — download the exact PDF your model references

Without an API, each step becomes custom ETL: join open-data tables, hunt PDF URLs, handle portal changes.

Solution: apicvm in your pipeline

Universe (tickers)
  → GET /v1/companies/resolve (batch per ticker)
  → GET /v1/documents?ticker=X&type=DFP|ITR|FRE&year=Y
  → GET /v1/documents/:id/file → object storage
  → (optional) POST /v1/document-text-extractions → NLP features
  → warehouse / feature store

Resolve issuers

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

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

Store cnpj, name, sector, and tickers[] as dimensions in your warehouse.

List filings for a panel

import os, requests, time

BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
TICKERS = ["PETR4", "VALE3", "WEGE3"]

rows = []
for ticker in TICKERS:
    for doc_type in ("DFP", "ITR"):
        r = requests.get(
            f"{BASE}/v1/documents",
            headers=H,
            params={"ticker": ticker, "type": doc_type, "year": 2024, "perPage": 50},
        )
        r.raise_for_status()
        for doc in r.json()["data"]:
            rows.append({
                "ticker": ticker,
                "type": doc["type"],
                "year": doc["year"],
                "date_ref": doc["dateRef"],
                "document_id": doc["id"],
                "name": doc["name"],
            })
    time.sleep(0.5)  # respect rate limits

Respect X-RateLimit-* headers in production schedulers.

Download to object storage

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

Store with a deterministic key: s3://research/cvm/{ticker}/{type}/{year}/{document_id}.pdf.

When to combine with open data

Many teams use CVM open data for historical cross-sections (500 companies × 10 years) and apicvm for:

  • On-demand filing fetch when a model flags an event
  • User-facing "download source" buttons
  • Text extraction for NLP features

See CVM Open Data vs apicvm API.

Current limitations

  • apicvm covers the ingested corpus — not guaranteed every B3 company or period.
  • No equity prices — pair with a market data provider for quotes.
  • No parsed financial line items — PDFs only; parsing is your pipeline's job.
  • Rate limits apply per API key — batch jobs need throttling.
  • Filings arrive after pipeline ingestion — not real-time CVM publication.

Next steps

Ready to integrate?

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