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.

Public JSON fields use camelCase (for example dateRef, idCompany). Internal fields such as url, status, createdAt, updatedAt, and allPagesDone are not returned in API responses.

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, etc.).

POST /v1/document-text-extractions

Queue async page-level markdown extraction.

Authentication

Send your API key on every business route. Prefer Bearer auth. Access is currently provisioned manually — there is no public self-serve signup on this site.

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.
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 via Redis. Default window: 60 seconds. Default max requests: 60 per window.

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" }

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).
types string Comma-separated list of types (e.g. DFP,ITR).
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 (DFP, ITR, FRE, etc.).
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 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" }
    ]
  }
}

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

Queue an async extraction job. Pages are delivered to your callback_url as markdown as they complete. There is no job status endpoint — progress arrives only via callbacks.

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 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 2024 DFP filings
curl -H "Authorization: Bearer $APICVM_KEY" \
  "$APICVM_URL/v1/documents?ticker=PETR4&type=DFP&year=2024"

# 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()

# List DFP filings for 2024
documents = requests.get(
    f"{BASE_URL}/v1/documents",
    params={"ticker": "PETR4", "type": "DFP", "year": 2024},
    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, the worker sends one callback per page to your callback_url. 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..."
  },
  "current_page": 1,
  "total_pages": 120,
  "is_last_page": false
}

Error callback

{
  "status": "error",
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "job_id": "job-uuid",
  "error_message": "Description of the error"
}
Field Type Description
status success | error Callback outcome.
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.markdown string Page content as markdown.
current_page integer Index of this callback (1-based).
total_pages integer Total pages in the document.
is_last_page boolean true on the final page callback.
error_message string Present when status is error.

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