Build a Streamlit Dashboard for Brazil CVM Filings
A small Streamlit CVM filings dashboard is a fast way to demo apicvm internally: pick a ticker, list filings, open PDFs. This uses Python requests + Streamlit — not an official Streamlit component.
Why this converts
Product and research teams often need a UI before they approve an API key budget. Streamlit ships that UI in ~50 lines against the same /v1 contract as production jobs.
Dependencies
pip install streamlit requests
export APICVM_URL='https://apicvm.dev'
export APICVM_KEY='apicvm_...'
App sketch
import os
import requests
import streamlit as st
BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
st.title("Brazil CVM filings")
ticker = st.text_input("Ticker", "PETR4").upper().strip()
doc_type = st.selectbox("Type", ["DFP", "ITR", "FRE"])
year = st.number_input("Year", min_value=2010, max_value=2030, value=2024)
if st.button("Load filings"):
company = requests.get(
f"{BASE}/v1/companies/resolve",
params={"query": ticker, "by": "ticker"},
headers=H,
timeout=30,
)
company.raise_for_status()
st.json(company.json())
docs = requests.get(
f"{BASE}/v1/documents",
params={"ticker": ticker, "type": doc_type, "year": int(year), "perPage": 20},
headers=H,
timeout=30,
)
docs.raise_for_status()
rows = docs.json().get("data") or []
for d in rows:
st.write(d["name"], d["id"])
st.markdown(f"[Download PDF]({BASE}/v1/documents/{d['id']}/file)")
Note: browser PDF links need the Authorization header — for downloads from the UI, fetch bytes server-side and use st.download_button instead of a naked URL:
pdf = requests.get(f"{BASE}/v1/documents/{d['id']}/file", headers=H, timeout=120)
st.download_button("PDF", pdf.content, file_name=f"{d['id']}.pdf")
Extend with FRE name filters
name = st.text_input("Name contains", "FatoresRisco")
params = {"ticker": ticker, "type": "FRE", "year": int(year), "name": name, "perPage": 20}
Cache resolve results
@st.cache_data(ttl=3600)
def resolve(ticker: str):
r = requests.get(
f"{BASE}/v1/companies/resolve",
params={"query": ticker, "by": "ticker"},
headers=H,
timeout=30,
)
r.raise_for_status()
return r.json()
Caching cuts rate-limit usage when users toggle years for the same issuer.
Show empty corpus honestly
If data is empty, display “Not in corpus for this filter” — not “company has no filings.” Ingestion lag is normal. Pair with Getting started for expected document types.
Security note
Streamlit Cloud secrets should store APICVM_KEY. Never put keys in st.session_state that gets logged. Prefer server-side st.download_button over exposing Bearer tokens in browser links.
Current limitations
- This dashboard lists ingested filings only.
- Do not embed API keys in Streamlit Cloud secrets shared publicly.
- Page-level OCR extraction remains async — keep it out of the first demo.
Next steps
Ready to integrate?
Get an API key and start querying Brazilian CVM filings programmatically.