API reference

Complete apicvm API documentation

Everything you need to integrate with Brazilian CVM filings: endpoints, query filters, response fields, error codes, and async text extraction callbacks.

Overview

All business routes use the prefix /v1. The base URL in production is https://apicvm.dev. Authenticate with an API key on every business route except GET /v1/health-check and the public demo routes under /v1/demo/*.

GET /v1/companies

List and filter public companies.

GET /v1/companies/resolve

Resolve a single company by ticker, CNPJ, or name.

GET /v1/documents

List and filter CVM filings: DFP, ITR, FRE, material facts, and IPE disclosures.

GET /v1/document-prefixes

List section-level name prefixes for DFP, ITR, or FRE.

POST /v1/document-text-extractions

Queue async page-level markdown extraction. Pro plan only.

Authentication

Send your API key on every business route. Prefer Bearer auth. Sign up at /signup to get a free 3-day API key after email verification, or upgrade to Student ($3/month) or Pro ($9/month).

Authorization: Bearer apicvm_...
# or
X-API-Key: apicvm_...
Header Required Description
Authorization Yes (business routes) Bearer apicvm_... — preferred method.
X-API-Key Alternative Same key value without the Bearer prefix.
Content-Type POST only application/json for text extraction requests.

Errors

All errors follow a consistent envelope:

{
  "error": {
    "code": "DOCUMENT_NOT_FOUND",
    "message": "Documento não encontrado",
    "details": {}
  }
}
Status Code When
401 UNAUTHORIZED Missing or invalid API key.
401 API_KEY_EXPIRED Free API key expired. Subscribe to Student or Pro to continue.
403 FORBIDDEN Plan does not allow this feature (e.g. markdown extraction on Free or Student).
404 COMPANY_NOT_FOUND No company matches the resolve query.
404 DOCUMENT_NOT_FOUND Document or file not found.
409 AMBIGUOUS_RESULT Resolve found multiple companies; see details.candidates.
422 VALIDATION_FAILED Invalid query params or request body.
429 RATE_LIMIT_EXCEEDED Per-key rate limit exceeded.
500 INTERNAL_SERVER_ERROR Unexpected server error.

Ambiguous company resolve returns 409 with a candidates array instead of picking a match silently.

Pagination and sorting

List endpoints accept these shared query parameters:

Parameter Type Default Description
page integer 1 Page number (1-based).
perPage integer 10 Items per page. Maximum 50.
field string varies Sort field. Must be a valid model attribute.
order asc | desc varies Sort direction.

Paginated responses use Lucid-style meta + data:

{
  "meta": {
    "total": 120,
    "perPage": 10,
    "currentPage": 1,
    "lastPage": 12,
    "firstPage": 1,
    "firstPageUrl": "...",
    "lastPageUrl": "...",
    "nextPageUrl": "...",
    "previousPageUrl": null
  },
  "data": [ ... ]
}

Default sort for companies: name asc. Default sort for documents: year desc, then dateRef desc, then name asc.

Rate limits

When authentication and rate limiting are enabled, limits apply per API key. Free and paid plans include a global limit of 60 requests per 60-second window.

Plan Price Global limit Daily cap Markdown extraction
Free $0 / 3 days 60 req / 60s Not available (403 FORBIDDEN)
Student $3/month 60 req / 60s 100 req / UTC day Not available (403 FORBIDDEN)
Pro $9/month 60 req / 60s Yes — page credits (see below)
Scale Custom By agreement By agreement

Markdown extraction (POST /v1/document-text-extractions) is available on Pro and Scale only. Free and Student plan requests receive 403 FORBIDDEN. Usage is billed in page credits (1 credit = 1 page).

Extraction credits

Pro includes 1000 credits/month that do not roll over. Prepaid packs: 1000 ($10) / 5000 ($50) / 10000 ($100) — packs do not expire. The POST returns 202 immediately; the prepare job counts pages (N) and checks balance. If balance < N, your callback receives status: "error" with error_code: EXTRACTION_CREDITS_EXCEEDED, balance, and required — nothing is debited and pages are not processed. Cache hits also consume N credits.

Header Description
X-RateLimit-Limit Maximum requests allowed in the current window.
X-RateLimit-Remaining Requests remaining in the current window.
X-RateLimit-Reset Unix timestamp when the window resets.

Health check

GET /v1/health-check

Public endpoint. No authentication required.

Response 200

{ "status": "ok" }

Public demo (VALE3)

Try Vale (VALE3) without an API key. The landing page includes a live runner, or call these routes directly. You can download the Vale FRE 2025 risk factors demo file (DescricaoFatoresRisco) or fetch its cached page markdown. Async extraction of other filings requires a paid plan.

GET /v1/demo/companies/resolve
GET /v1/demo/documents
GET /v1/demo/documents/:id
GET /v1/demo/documents/:id/file
GET /v1/demo/documents/:id/markdown
GET /v1/demo/document-prefixes

Scope: CNPJ 33592510000154 only. File download and cached markdown are limited to FRE 2025 section DescricaoFatoresRisco. Rate limit by IP (30 req/min, 200 req/day). perPage on document list is capped at 20.

GET /v1/demo/companies/resolve?query=VALE3&by=ticker
GET /v1/demo/documents?ticker=VALE3&type=FRE&year=2025&name=DescricaoFatoresRisco&perPage=5
GET /v1/demo/documents/{id}/file
GET /v1/demo/documents/{id}/markdown
GET /v1/demo/document-prefixes?type=FRE

List companies

GET /v1/companies

Returns a paginated list of Brazilian public companies with tickers.

Query parameters

Parameter Type Description
id integer Filter by company ID.
search string Search by name, sector, or CNPJ (partial match).
ticker string Filter by ticker (case-insensitive).
cnpj string Filter by CNPJ. Accepts formatted or digits-only.
name string Partial match on company name.
status ACTIVE | INACTIVE Filter by company status.
page, perPage, field, order Pagination and sorting (see above).

Response fields (data[])

Field Type Description
id integer Company ID.
name string Legal company name.
cnpj string CNPJ (digits only).
sector string | null Industry sector when available.
tickers[] array List of tickers. Each item has id, idCompany, ticker, tickerClass.

Example

GET /v1/companies?search=Petrobras&perPage=5
{
  "meta": { "total": 1, "perPage": 5, "currentPage": 1, "lastPage": 1 },
  "data": [
    {
      "id": 42,
      "name": "Petróleo Brasileiro S.A. - Petrobras",
      "cnpj": "33000167000101",
      "sector": "Petróleo, Gás e Biocombustíveis",
      "tickers": [
        { "id": 1, "idCompany": 42, "ticker": "PETR4", "tickerClass": "ON" }
      ]
    }
  ]
}

Resolve company

GET /v1/companies/resolve

Find a single company by ticker, CNPJ, or name. Returns one match or an ambiguity error with candidates.

Query parameters

Parameter Type Required Description
query string Yes Ticker, CNPJ, or company name.
by auto | ticker | cnpj | name No Resolution strategy. Default: auto.

Resolution order (by=auto)

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

Response fields

Same shape as a single company object from the list endpoint.

Example — success

GET /v1/companies/resolve?query=PETR4&by=ticker
{
  "id": 42,
  "name": "Petróleo Brasileiro S.A. - Petrobras",
  "cnpj": "33000167000101",
  "sector": "Petróleo, Gás e Biocombustíveis",
  "tickers": [
    { "id": 1, "idCompany": 42, "ticker": "PETR4", "tickerClass": "ON" }
  ]
}

Example — ambiguous (409)

{
  "error": {
    "code": "AMBIGUOUS_RESULT",
    "message": "Mais de uma empresa corresponde à busca",
    "details": {
      "candidates": [
        { "id": 10, "name": "...", "cnpj": "...", "sector": null, "tickers": ["ABC3"] },
        { "id": 11, "name": "...", "cnpj": "...", "sector": null, "tickers": ["ABC4"] }
      ]
    }
  }
}

List documents

GET /v1/documents

Returns a paginated list of CVM filings. Filter by company, ticker, type, year, and more. Each item includes nested company with tickers.

Query parameters

Parameter Type Description
id UUID string Filter by document ID.
companyId integer Filter by company ID.
ticker string Filter by company ticker (case-insensitive).
cnpj string Filter by company CNPJ. Accepts formatted or digits-only.
companyName string Partial match on company name.
search string Search document name or type (partial match).
year integer Filter by filing year (2000–2100).
type string Filter by single document type (e.g. DFP, ITR, FRE, FATO_RELEVANTE).
types string Comma-separated list of types (e.g. DFP,ITR,FATO_RELEVANTE).
dateRef string Filter by reference date (YYYY-MM-DD). Use Sem data for documents without a date.
name string Partial match on document name.
page, perPage, field, order Pagination and sorting (see above).

Response fields (data[])

Field Type Description
id UUID string Document ID.
type string Document type. See the reference table below.
dateRef string | null Reference date (YYYY-MM-DD).
idCompany integer Company ID.
year integer Filing year.
name string | null Document display name.
hash string | null Content hash when available.
company object Nested company with id, name, cnpj, sector, tickers[].

Example

GET /v1/documents?ticker=PETR4&type=DFP&year=2024&perPage=20
GET /v1/documents?ticker=VALE3&type=FATO_RELEVANTE&year=2025&perPage=20

Document types

GET /v1/documents accepts all document types below. IPE documents are single PDFs from RAD: the document name comes from the filing subject/protocol, and dateRef is the delivery date.

Type Description
DFP Annual standardized financial statements.
ITR Quarterly financial information.
FRE Reference form: company profile, risk factors, governance, compensation, and related sections.
FATO_RELEVANTE Material facts disclosed through the IPE feed.
COMUNICADO_AO_MERCADO Market announcements, excluding investor presentations.
APRESENTACAO_INVESTIDORES Investor presentations filed as market announcements.
AVISO_AOS_ACIONISTAS Notices to shareholders.
ATA_ASSEMBLEIA Shareholder meeting minutes.

Get document

GET /v1/documents/:id

Returns metadata for a single document, including nested company and tickers.

Path parameters

Parameter Type Description
id UUID string Document ID from a list or resolve flow.

Example

GET /v1/documents/550e8400-e29b-41d4-a716-446655440000
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "DFP",
  "dateRef": "2024-12-31",
  "idCompany": 42,
  "year": 2024,
  "name": "DFP 2024",
  "hash": null,
  "company": {
    "id": 42,
    "name": "Petróleo Brasileiro S.A. - Petrobras",
    "cnpj": "33000167000101",
    "sector": "Petróleo, Gás e Biocombustíveis",
    "tickers": [
      { "id": 1, "idCompany": 42, "ticker": "PETR4", "tickerClass": "ON" }
    ]
  }
}

Document prefixes

GET /v1/document-prefixes

Returns the catalog of distinct section-level name prefixes for DFP, ITR, and FRE. Use this when you need to discover which FRE/DFP/ITR sections exist before filtering GET /v1/documents with the name parameter.

Prefixes are derived from document names: the segment before the first -, with digits and underscores removed. For example, DescricaoFatoresRisco-4_1 becomes DescricaoFatoresRisco.

IPE document types such as FATO_RELEVANTE are single PDFs and do not have prefixes.

Query parameters

Parameter Type Description
type string (required) Document type. One of DFP, ITR, or FRE.

Response

{
  "data": [
    "DescricaoControlesInternos",
    "DescricaoFatoresRisco",
    "DescricaoGerenciamentoRiscos",
    "DescricaoRiscosMercado",
    "PoliticaPraticaRemuneracao"
  ]
}

Example

GET /v1/document-prefixes?type=FRE

Then filter documents with a prefix:

GET /v1/documents?ticker=PETR4&type=FRE&year=2024&name=DescricaoFatoresRisco

Download file

GET /v1/documents/:id/file

Streams the original CVM filing file from storage. Useful when you need the source PDF, not just metadata or extracted text.

Response headers

Header Description
Content-Type application/pdf, text/plain, or application/octet-stream.
Content-Length File size in bytes.
Content-Disposition inline; filename="..."
Cache-Control private, max-age=300

Example

curl -OJ -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents/550e8400-e29b-41d4-a716-446655440000/file"

Text extraction

POST /v1/document-text-extractions

Accepts the request with 202 immediately. Page count, credit gate, and debit run in a prepare job; pages are then delivered to your callback_url as markdown. There is no job status endpoint — progress arrives only via callbacks. Pro plan only. Debits N page credits in prepare (cache hits included). Insufficient balance is reported via callback error_code: EXTRACTION_CREDITS_EXCEEDED. Free and Student plans receive 403 FORBIDDEN.

Request body

Field Type Required Description
callback_url string (URL) Yes HTTPS URL that receives page callbacks. Must include protocol.
document.id UUID string Yes Document ID to extract.

Example request

POST /v1/document-text-extractions
Content-Type: application/json

{
  "callback_url": "https://you.example.com/callbacks/apicvm",
  "document": {
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Response 202

{
  "id": "job-uuid",
  "status": "queued",
  "document_id": "550e8400-e29b-41d4-a716-446655440000"
}

If the document was already fully extracted and cached, the worker reuses existing page text and sends callbacks from cache.

Examples

Recommended agent flow: resolve company → list section prefixes (optional) → list documents → pick an explicit id → download file or enqueue extraction.

cURL

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

# List FRE section prefixes
curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/document-prefixes?type=FRE"

# List FRE risk-factor sections for 2024
curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=PETR4&type=FRE&year=2024&name=DescricaoFatoresRisco"

# List material facts
curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=VALE3&type=FATO_RELEVANTE&year=2025"

# Download original file
curl -OJ -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents/$DOCUMENT_ID/file"

# Queue text extraction
curl -X POST -H "Authorization: Bearer $APICVM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"callback_url":"https://you.example.com/cb","document":{"id":"'"$DOCUMENT_ID"'"}}' \
  "$APICVM_URL/v1/document-text-extractions"

Python

import os
import requests

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

# Resolve company
company = requests.get(
    f"{BASE_URL}/v1/companies/resolve",
    params={"query": "PETR4", "by": "ticker"},
    headers=HEADERS,
).json()

# Discover FRE section prefixes, then filter risk-factor documents
prefixes = requests.get(
    f"{BASE_URL}/v1/document-prefixes",
    params={"type": "FRE"},
    headers=HEADERS,
).json()
print(prefixes["data"][:5])

documents = requests.get(
    f"{BASE_URL}/v1/documents",
    params={
        "ticker": "PETR4",
        "type": "FRE",
        "year": 2024,
        "name": "DescricaoFatoresRisco",
    },
    headers=HEADERS,
).json()

document_id = documents["data"][0]["id"]

# Download original PDF
pdf = requests.get(
    f"{BASE_URL}/v1/documents/{document_id}/file",
    headers=HEADERS,
)
pdf.raise_for_status()

# Queue text extraction
job = requests.post(
    f"{BASE_URL}/v1/document-text-extractions",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={
        "callback_url": "https://you.example.com/callbacks/apicvm",
        "document": {"id": document_id},
    },
)
job.raise_for_status()
print(job.json())  # {"id": "...", "status": "queued", "document_id": "..."}

TypeScript

const baseUrl = process.env.APICVM_URL!
const apiKey = process.env.APICVM_KEY!

async function apicvmGet(path: string) {
  const response = await fetch(`${baseUrl}${path}`, {
    headers: { Authorization: `Bearer ${apiKey}` },
  })
  if (!response.ok) throw new Error(await response.text())
  return response.json()
}

const company = await apicvmGet('/v1/companies/resolve?query=PETR4&by=ticker')
const documents = await apicvmGet('/v1/documents?ticker=PETR4&type=DFP&year=2024')
const documentId = documents.data[0].id

const extraction = await fetch(`${baseUrl}/v1/document-text-extractions`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    callback_url: 'https://you.example.com/callbacks/apicvm',
    document: { id: documentId },
  }),
})

Extraction callbacks

After a successful POST /v1/document-text-extractions, page workers send one callback per page (possibly out of order). When all pages finish, the parent job sends status: "completed". Callbacks have retry logic (up to 3 attempts). Your endpoint should be idempotent.

Page callback (success)

{
  "status": "success",
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_id": "job-uuid",
  "page": {
    "number": 1,
    "markdown": "# Demonstrações Financeiras\n\n..."
  },
  "total_pages": 120
}

Document completed

{
  "status": "completed",
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_id": "job-uuid",
  "total_pages": 120
}

Error callback

{
  "status": "error",
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_id": "job-uuid",
  "error_message": "Description of the error"
}

Insufficient credits (from the prepare job):

{
  "status": "error",
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_id": "job-uuid",
  "error_code": "EXTRACTION_CREDITS_EXCEEDED",
  "error_message": "Créditos de extração insuficientes",
  "balance": 12,
  "required": 120
}
Field Type Description
status success | completed | error Callback outcome. Use completed to mark the document ready.
document_id UUID string Document being extracted.
job_id string Extraction job ID from the 202 response.
page.number integer 1-based page number (page callbacks only).
page.markdown string Page content as markdown (page callbacks only).
total_pages integer Total pages in the document.
error_message string Present when status is error.
error_code string Optional. EXTRACTION_CREDITS_EXCEEDED when balance < pages required.
balance / required integer Present with EXTRACTION_CREDITS_EXCEEDED.

For AI agents

Download llms.txt for a plain-text summary of this API — endpoints, filters, examples, and limitations — optimized for LLM and agent consumption without parsing HTML.

llms.txt

Machine-readable API reference. Point your agent at https://apicvm.dev/llms.txt or download the file locally.

Download llms.txt