List Brazil DFP Annual Filings (10-K Equivalent) via API

Brazil does not have a 10-K. If you are looking for a Brazil 10-K API, the CVM filing that carries the audited annual statements is DFP (Demonstrações Financeiras Padronizadas). apicvm lists those documents with type=DFP. It does not accept type=10-K.

This guide shows how to resolve a ticker, list the DFP bundle for a year, pick a file by name, and download the original PDF.

The problem

EDGAR pipelines filter by form type. The annual report query is 10-K. Point that same filter at CVM and you get nothing useful: the regulator never named the form that way.

Two extra traps show up in English-language material:

  • Multi-market aggregators sometimes expose Brazilian annual reports under a normalized 10-K label. That label is theirs, not CVM's. On apicvm the native type is DFP.
  • Some issuer IR pages describe the Formulário de Referência (FRE) as "similar to a 10-K" because it holds business, risk, and governance narrative. FRE is the other half of what a US 10-K contains. It is not the audited financial statements.

If you need the annual numbers, list DFP. If you need the narrative 10-K items, list FRE. Mixing them in one 10-K bucket hides which file you actually got.

DFP vs the rest of the 10-K mental model

CVM is Brazil's securities regulator. The workflow is close to EDGAR (resolve issuer, list filings, fetch the file), but the taxonomy is Brazilian. There is no official mapping to SEC forms.

You want CVM type Closest EDGAR role
Audited annual financials DFP 10-K financial statements
Business, risk, governance narrative FRE 10-K items 1 / 1A / 7, plus proxy-like sections
Quarterly financials ITR 10-Q. ITR here is Informações Trimestrais (Brazilian quarterly filings), not an income tax return
Material event disclosures FATO_RELEVANTE Closer to an 8-K than to a 10-K

A DFP year is usually a bundle, not one PDF: statements, explanatory notes, management report, auditor opinion, director declarations. List first, then filter by name.

How apicvm helps

  1. Resolve the issuer — GET /v1/companies/resolve
  2. List the annual bundle — GET /v1/documents?type=DFP
  3. Optional: discover section prefixes — GET /v1/document-prefixes?type=DFP
  4. Download the PDF — GET /v1/documents/:id/file
  5. Optional (Pro): enqueue page-level markdown — POST /v1/document-text-extractions

Auth: Authorization: Bearer or X-API-Key.

Setup

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

The public demo API is scoped to VALE3 FRE 2025 risk factors. It will not return PETR4 DFP files. Use a real key for this flow.

Step 1: Resolve the company

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

Confirm cnpj and tickers[] before you store anything. A name query that matches more than one issuer returns 409 AMBIGUOUS_RESULT with candidates. Tighten it with by=ticker or by=cnpj.

Step 2: List DFP filings

Filter by ticker, type, and year. perPage maxes out at 50.

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=PETR4&type=DFP&year=2024&perPage=50&field=dateRef&order=desc"

Each data[] item carries id (UUID), type, year, name, dateRef, and a nested company with tickers. Persist the UUID. Display names are long Portuguese section titles and are not stable identifiers.

dateRef on a DFP is typically the fiscal year-end (for example 2024-12-31). Empty data for a large issuer is usually a corpus gap for that year, not an unsupported type.

Narrow the bundle by name

If you only need notes or the auditor package, do not download every row. Prefixes for DFP (and ITR / FRE) come from:

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/document-prefixes?type=DFP"

The response is { "data": ["...", "..."] } — distinct name prefixes in the ingested corpus. Pass a partial name on the documents list to keep one annex:

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=PETR4&type=DFP&year=2024&name=DeclaracaoDiretoresRelatorioAuditorIndependente&perPage=20"

More on this pattern: Filter CVM filings by section name and DFP/ITR notes and management reports.

Need the quarterly package in the same year? See List Brazil ITR filings (10-Q equivalent): type=ITR (Informações Trimestrais, not income tax), or the comma-separated types=DFP,ITR filter. Pagination details are in Paginate and filter CVM documents.

Step 3: Download the PDF

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

File download does not consume extraction credits. The bytes are the original filing (usually application/pdf), not parsed line items or XBRL.

Example: Python

import os
import requests

BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}

company = requests.get(
    f"{BASE}/v1/companies/resolve",
    params={"query": "PETR4", "by": "ticker"},
    headers=H,
    timeout=60,
)
company.raise_for_status()

docs = requests.get(
    f"{BASE}/v1/documents",
    params={
        "ticker": "PETR4",
        "type": "DFP",
        "year": 2024,
        "perPage": 50,
        "field": "dateRef",
        "order": "desc",
    },
    headers=H,
    timeout=60,
)
docs.raise_for_status()

for row in docs.json()["data"]:
    print(row["id"], row.get("dateRef"), row.get("name"))

A watchlist is the same call in a loop over tickers, one page at a time. See Build a multi-ticker CVM filings watchlist.

Getting numbers out of the DFP

The list endpoint returns metadata and the original PDF. It does not return revenue, net income, or a balance-sheet schema. There is no XBRL object in the JSON.

Two ways to go further:

  • Parse the PDF yourself after GET /v1/documents/:id/file
  • On Pro, enqueue page-level markdown with POST /v1/document-text-extractions and read the statements in a model. Extraction is asynchronous: you get 202 immediately, progress arrives on an HTTPS callback_url, and there is no job-status GET. Cache hits still debit one credit per page. Free and Student keys receive 403 FORBIDDEN.

See Extract text from CVM PDFs and async callbacks.

If you want bulk CSV across many issuers for a one-off academic load, CVM open data ZIP dumps may be a better fit than per-ticker HTTP. That comparison is in CVM open data vs apicvm.

When FRE is the filing you actually wanted

A US 10-K mixes financial statements with Item 1 (business), Item 1A (risk factors), and Item 7 (MD&A). In Brazil those narrative blocks live in the FRE, not in the DFP package.

curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=PETR4&type=FRE&year=2024&name=DescricaoFatoresRisco&perPage=5"

Start from List Formulário de Referência (FRE) via API if the goal is risk factors or governance rather than the income statement. Definition: What is FRE?.

For the mapping across the whole CVM set, see Brazil CVM vs SEC EDGAR. New to the product API? CVM API overview.

Current limitations

  • GET /v1/documents does not accept type=10-K. Use DFP.
  • Coverage depends on the ingestion sync. Empty results can be a gap, not an API error.
  • No push feed for "a new DFP arrived"; clients poll GET /v1/documents.
  • No structured financial line items in the JSON. Numbers are inside the PDF.
  • Do not expect real-time delivery; latency follows the sync pipeline.
  • Demo routes do not expose DFP downloads beyond the VALE3 FRE demo scope.
  • apicvm covers Brazilian CVM filings only. It does not replace EDGAR for US issuers.

Next steps

Ready to integrate?

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