Access Brazil CVM Filings with Java
Need a Java CVM filings API client for Brazilian public companies? apicvm is plain HTTPS JSON. Use java.net.http.HttpClient, a Bearer token, and the /v1/* routes — there is no official Java SDK.
The problem
JVM services that need CVM filings often end up:
- Wrapping brittle portal scrapers in Selenium
- Parsing local ZIP dumps without stable document IDs
- Reimplementing auth for every microservice language
A typed HTTP client against a fixed contract is easier to keep in Spring Boot or Quarkus CI.
Setup
export APICVM_URL='https://apicvm.dev'
export APICVM_KEY='apicvm_...' # from /signup
Java 11+ is enough (HttpClient is in the JDK). Add Jackson (or Gson) if you want POJOs; the examples below use String + JsonNode from Jackson.
Resolve a ticker
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
public class ResolveTicker {
static final ObjectMapper MAPPER = new ObjectMapper();
public static void main(String[] args) throws Exception {
String base = System.getenv("APICVM_URL");
String key = System.getenv("APICVM_KEY");
String url = base + "/v1/companies/resolve?query="
+ URLEncoder.encode("PETR4", StandardCharsets.UTF_8)
+ "&by=ticker";
HttpRequest req = HttpRequest.newBuilder(URI.create(url))
.timeout(Duration.ofSeconds(30))
.header("Authorization", "Bearer " + key)
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() >= 400) {
throw new RuntimeException("HTTP " + res.statusCode() + ": " + res.body());
}
JsonNode company = MAPPER.readTree(res.body());
System.out.println(company.toPrettyString());
}
}
List DFP documents
String listUrl = base + "/v1/documents?ticker=PETR4&type=DFP&year=2024&perPage=20";
HttpRequest listReq = HttpRequest.newBuilder(URI.create(listUrl))
.header("Authorization", "Bearer " + key)
.GET()
.build();
JsonNode docs = MAPPER.readTree(
HttpClient.newHttpClient()
.send(listReq, HttpResponse.BodyHandlers.ofString())
.body());
for (JsonNode row : docs.path("data")) {
System.out.println(row.path("id").asText() + " " + row.path("name").asText());
}
perPage max is 50. Paginate with page until meta.lastPage. See Paginate and filter CVM documents.
Download a PDF
import java.nio.file.Files;
import java.nio.file.Path;
String docId = "..."; // UUID from list response
HttpRequest fileReq = HttpRequest.newBuilder(
URI.create(base + "/v1/documents/" + docId + "/file"))
.header("Authorization", "Bearer " + key)
.GET()
.build();
byte[] pdf = HttpClient.newHttpClient()
.send(fileReq, HttpResponse.BodyHandlers.ofByteArray())
.body();
Files.write(Path.of("petr4-dfp.pdf"), pdf);
File download does not consume extraction credits.
curl cross-check
curl -H "Authorization: Bearer $APICVM_KEY" \
"$APICVM_URL/v1/companies/resolve?query=PETR4&by=ticker"
Errors and rate limits
Map status codes in your exception hierarchy: 401 auth, 404 missing document, 429 rate limit. Read X-RateLimit-Remaining when fan-out across tickers. Details: Handle errors and rate limits.
Current limitations
- Text extraction (
POST /v1/document-text-extractions) is async via HTTPS callback — not a sync Java return value. perPagemax is 50.- Corpus coverage depends on ingestion lag; resolve before hard-coding CNPJ.
Next steps
Ready to integrate?
Get an API key and start querying Brazilian CVM filings programmatically.