Resolve Brazilian Companies by Ticker, CNPJ, or Name

Every CVM filings workflow starts with one question: which company is this? A Brazil company lookup API should resolve PETR4, a CNPJ, or a partial legal name into stable metadata before you list documents. apicvm exposes GET /v1/companies/resolve for exactly that — the first step in the recommended filings flow.

This guide covers resolution modes, ambiguity handling, and how resolve connects to document listing.

The problem

Brazilian issuers appear under multiple identifiers:

  • TickersITUB4, BBAS3 (B3-listed symbols)
  • CNPJ — 14-digit corporate tax ID (with or without formatting)
  • Legal names — "ITAÚ UNIBANCO HOLDING S.A." or partial matches

CVM open-data dumps are CNPJ-centric. Product code is ticker-centric. Without a resolve step, you maintain your own mapping tables or guess which company a filter returns.

How resolve works

GET /v1/companies/resolve finds one company per request.

Parameter Required Description
query Yes Ticker, CNPJ, or name
by No auto (default), ticker, cnpj, or name

Resolution order (by=auto)

  1. Ticker (case-insensitive)
  2. CNPJ (formatted or digits only)
  3. Exact name (case-insensitive)
  4. Partial name match

Force a mode when you know the identifier type: by=ticker, by=cnpj, or by=name.

Response shape

Success (200) returns a company object:

Field Type Example
id integer Internal company ID
name string Legal name
cnpj string Digits only
sector string \ null Industry sector
tickers array { id, idCompany, ticker, tickerClass }

Use id for companyId filters on GET /v1/documents, or pass ticker/cnpj directly in document queries.

Example: resolve by ticker

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

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

Example: resolve by CNPJ

CNPJ works with or without punctuation:

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

Returns Itaú Unibanco Holding (ITUB4).

Example: Python with error handling

import os, requests

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

def resolve(query: str, by: str = "auto") -> dict:
    r = requests.get(
        f"{BASE}/v1/companies/resolve",
        headers=H,
        params={"query": query, "by": by},
    )
    if r.status_code == 409:
        candidates = r.json()["error"]["details"]["candidates"]
        raise ValueError(f"Ambiguous: {len(candidates)} matches")
    r.raise_for_status()
    return r.json()

company = resolve("BBAS3", by="ticker")
print(company["name"], company["cnpj"])

Handling ambiguity (409)

When multiple companies match, the API returns 409 AMBIGUOUS_RESULT with details.candidates[]. It never silently picks one.

Common fixes:

  • Use by=ticker or by=cnpj for unambiguous identifiers
  • Narrow a name query ("BANCO DO BRASIL" vs "BANCO")
  • Present candidates to the user and retry with a specific CNPJ

After resolve: list documents

Once you have the company, list filings:

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

Alternatively, filter by companyId from the resolve response.

List companies (browse mode)

To search or paginate the full universe, use GET /v1/companies with filters like search, ticker, cnpj, name, and status=ACTIVE. Resolve is for point lookups; list is for discovery.

Current limitations

  • Resolve returns companies in the ingested corpus — not every B3-listed symbol may be present yet.
  • Partial name matches can trigger ambiguity; prefer ticker or CNPJ in automated pipelines.
  • Resolve does not return filing counts or document metadata — follow with GET /v1/documents.

Next steps

Ready to integrate?

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