Orchestrate Brazil CVM Filings with Airflow
Need Airflow CVM filings jobs that stay reproducible? Schedule apicvm calls in a DAG: resolve companies, list documents by ticker/type/year, download PDFs to object storage, and optionally enqueue text extraction. apicvm is the HTTP source; Airflow owns retries and schedules.
The problem
Nightly Brazil filing pulls usually fail for operational reasons:
- Manual portal downloads do not retry or alert
- Ad-hoc scripts ignore
429andX-RateLimit-* - No audit trail of which
document.idlanded in the lake
Airflow + a stable filings API fixes the ops layer without scraping HTML.
Pattern
Variable: ticker watchlist
→ GET /v1/companies/resolve
→ GET /v1/documents (DFP/ITR/FRE, paginated)
→ GET /v1/documents/:id/file → S3/GCS
→ optional POST /v1/document-text-extractions
Store APICVM_KEY in an Airflow connection or secret backend — never in DAG code.
Minimal Python task
import os, requests
BASE = os.environ["APICVM_URL"] # https://apicvm.dev
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
def list_dfp(ticker: str, year: int = 2024):
page, rows = 1, []
while True:
r = requests.get(
f"{BASE}/v1/documents",
headers=H,
params={
"ticker": ticker,
"type": "DFP",
"year": year,
"page": page,
"perPage": 50,
},
timeout=60,
)
r.raise_for_status()
payload = r.json()
rows.extend(payload.get("data") or [])
meta = payload.get("meta") or {}
if page >= int(meta.get("lastPage") or 1):
break
page += 1
return rows
Wire this into a @task or PythonOperator. Paginate as in Paginate and filter CVM documents.
Sketch DAG
from airflow import DAG
from airflow.decorators import task
from datetime import datetime
with DAG(
"cvm_filings_nightly",
start_date=datetime(2026, 1, 1),
schedule="@daily",
catchup=False,
) as dag:
@task
def pull_watchlist():
tickers = ["PETR4", "VALE3", "HYPE3"]
out = {}
for t in tickers:
out[t] = [d["id"] for d in list_dfp(t)]
return out
pull_watchlist()
Add a second task that downloads each id with GET /v1/documents/{id}/file and writes to your bucket. File download does not consume extraction credits.
Rate limits and retries
- Prefer Airflow retries with exponential backoff on
429/5xx - Space ticker loops; check
X-RateLimit-Remaining - Do not fan out hundreds of parallel tasks against one key
Extraction (optional)
POST /v1/document-text-extractions returns 202 and delivers page markdown to your HTTPS callback. Airflow should treat extraction as fire-and-confirm-via-callback, not as a sync XCom value. Same pattern as GitHub Actions monitor for lighter schedules.
curl smoke test
export APICVM_KEY='apicvm_...'
export APICVM_URL='https://apicvm.dev'
curl -H "Authorization: Bearer $APICVM_KEY" \
"$APICVM_URL/v1/documents?ticker=PETR4&type=ITR&year=2024&perPage=5"
Current limitations
- No job-status polling endpoint for extractions — callbacks only.
- Corpus ≠ live CVM portal; schedule lag is possible.
perPagemax 50.
Next steps
Ready to integrate?
Get an API key and start querying Brazilian CVM filings programmatically.