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/*.
List and filter public companies.
Resolve a single company by ticker, CNPJ, or name.
List and filter CVM filings: DFP, ITR, FRE, material facts, and IPE disclosures.
List section-level name prefixes for DFP, ITR, or FRE.
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
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.
/v1/demo/companies/resolve
/v1/demo/documents
/v1/demo/documents/:id
/v1/demo/documents/:id/file
/v1/demo/documents/:id/markdown
/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
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
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)
- Exact ticker match (case-insensitive).
- CNPJ match (formatted or digits-only).
- Exact name match (case-insensitive).
- 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
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
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
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
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
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.