Performance Guide

Endpoint Speed Reference

EndpointSpeedUse Case
GET /catalog~1sBrowse all authorized Symbols and descriptions
GET /info/{symbol}~0.5sGet metadata for a specific file
GET /download/{symbol}~0.5s + transferDownload a specific file
GET /list~2sVerify file existence with size and timestamp
GET /count~2sCount total accessible files

Downloading a known file

If you already know the Symbol:

# Direct download — fastest path
GET /download/IbgePnadAgricultureStk

Discovering and downloading files

# Step 1: Browse catalog (~1s) — find the Symbol you need
GET /catalog
# Returns: [{ "Symbol": "IbgePnadAgricultureStk", "Description": "..." }, ...]

# Step 2: Download by Symbol (~0.5s + transfer)
GET /download/IbgePnadAgricultureStk

Verifying which files exist

# Use /list when you need to confirm files exist in R2 with metadata
GET /list?limit=1000
# ~2s with batched HEAD calls — returns Symbol, size, upload date

Quick file count

GET /count
# ~2s, returns total number of accessible files

Token Caching

Tokens are valid for 1 hour. Do not request a new token on every API call — cache it and refresh when it is ~60 seconds from expiry.

# Good — reuse token until near-expiry
if not self.access_token or self.token_expires_at < datetime.now():
    self.access_token = fetch_new_token()

# Bad — fetches a new token on every request
token = fetch_new_token()
call_api(token)

Parallelism

/list and /count internally make batched parallel HEAD requests against R2 — they are already optimized. For downloading multiple files, parallelize client-side:

from concurrent.futures import ThreadPoolExecutor

symbols = ["SymbolA", "SymbolB", "SymbolC"]

with ThreadPoolExecutor(max_workers=5) as executor:
    futures = [executor.submit(client.download_file, s, f"{s}.parquet") for s in symbols]
    for f in futures:
        f.result()