Build a Multi-Ticker CVM Filings Watchlist

A CVM filings watchlist API pattern is simple: keep a ticker list, poll GET /v1/documents on a schedule, and diff against the last seen document.id set. apicvm does not ship a “new filing” webhook — polling is the supported approach.

The persona

  • Quant and agent builders tracking a Brazil universe
  • Product teams showing “latest filings” for a user portfolio
  • Researchers refreshing DFP/ITR after earnings season

The problem

You care about many tickers, not one curl. Without a watchlist loop you either over-fetch (rate limits) or miss documents. Some vendors advertise push webhooks within seconds of publication; apicvm’s contract is request/response + extraction callbacks, not a live CVM firehose.

Solution: poll + diff

Load watchlist tickers
For each ticker (throttle to stay under rate limit):
  GET /v1/documents?ticker=...&types=DFP,ITR,FRE&year=current
  Diff ids vs local store
  Enqueue download/extract for new ids
Sleep until next interval

Example: Python watchlist pass

import os, time, requests
from datetime import datetime

BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
WATCH = ["PETR4", "VALE3", "ABEV3", "JBSS3", "RENT3"]
YEAR = datetime.utcnow().year
seen = set()  # persist this in Redis/DB in production

def list_docs(ticker):
    r = requests.get(
        f"{BASE}/v1/documents",
        headers=H,
        params={"ticker": ticker, "types": "DFP,ITR,FRE", "year": YEAR, "perPage": 50},
    )
    if r.status_code == 429:
        reset = r.json().get("error", {}).get("details", {}).get("resetAt")
        time.sleep(5 if not reset else max(1, int(reset) - int(time.time())))
        return list_docs(ticker)
    r.raise_for_status()
    return r.json()["data"]

new_items = []
for t in WATCH:
    for d in list_docs(t):
        if d["id"] not in seen:
            seen.add(d["id"])
            new_items.append((t, d["type"], d["name"], d["id"]))
    time.sleep(1)  # polite spacing inside the 60 req / 60s window

print("new:", len(new_items))
for row in new_items[:10]:
    print(row)

Tune time.sleep and batch size to your plan’s rate limit. Standard Student/Pro windows are 60 requests per 60 seconds.

What to store

Field Why
document.id Stable primary key for diffs
ticker, type, year Routing / UI
name, dateRef Human label
hash (if present) Optional change detection

Current limitations

  • No native new-filing webhook in v1.
  • Extraction callbacks notify page progress for a job you started — they are not market-wide filing alerts.
  • Corpus lag means a document can exist on the CVM portal before it appears in apicvm.

Next steps

Ready to integrate?

Get an API key and start querying Brazilian CVM filings programmatically.