ffiec-data-connect (Python)
Quickstart
Your first FFIEC data call in under two minutes — fetch a bank's full Call Report facsimile as a pandas DataFrame.
By the end of this page you’ll have pulled one institution’s full Call Report for a quarter and loaded it into a DataFrame.
Prerequisites
- Installed
ffiec-data-connect3.0.0 or later (pip install ffiec-data-connect). - A JWT token from the FFIEC portal, loaded into
FFIEC_USERNAMEandFFIEC_BEARER_TOKENenvironment variables.
First call
import os
from ffiec_data_connect import OAuth2Credentials, collect_reporting_periods, collect_data
creds = OAuth2Credentials(
username=os.environ["FFIEC_USERNAME"],
bearer_token=os.environ["FFIEC_BEARER_TOKEN"],
)
# 1. What periods are available?
periods = collect_reporting_periods(creds, series="call", output_type="list")
print(periods[-5:])
# e.g. ['9/30/2025', '12/31/2025', '3/31/2026', ...]
# 2. Pull one bank's Call Report for the most recent period.
# RSSD 480228 is JPMorgan Chase Bank, N.A.
data = collect_data(
creds,
rssd_id="480228",
reporting_period=periods[-1],
series="call",
output_type="pandas",
force_null_types="pandas", # keep integers as integers
)
print(data.shape)
print(data.head())
What you got back
A DataFrame with one row per MDRM line item in the facsimile. The columns are:
| Column | Meaning |
|---|---|
mdrm | Line-item identifier (e.g. RCON2170 = total assets). |
rssd | Reporting institution’s RSSD. |
quarter | Reporting period (string in the original MM/DD/YYYY format by default). |
data_type | int, float, bool, or str — which typed column holds the value. |
int_data | Integer value, if data_type == "int". |
float_data | Float value, if data_type == "float". |
bool_data | Boolean value, if data_type == "bool". |
str_data | String value, if data_type == "str". |
Each row contains exactly one non-null typed value, indicated by data_type.
Looking up a specific line item
Total assets is MDRM RCON2170:
total_assets_row = data.loc[data["mdrm"] == "RCON2170"].iloc[0]
print(f"Total assets: ${total_assets_row['int_data']:,} thousand")
USD values in the XBRL facsimile are reported in thousands and stored as integers by the library (divided by 1000 during XBRL processing).
A second bank
# RSSD 37 is Cambridge Trust Company — a small community bank, useful for
# comparing against a money-center bank.
small_bank = collect_data(
creds,
rssd_id="37",
reporting_period=periods[-1],
series="call",
output_type="pandas",
force_null_types="pandas",
)
What to read next
- Output formats — list vs pandas vs polars; dates; nulls.
- Bulk download — do this for many institutions.
- Async and rate limits — the 2500/hour ceiling.
- Troubleshooting — common first-call failures.
Prefer a notebook? The upstream
ffiec_data_connect_rest_demo.ipynb
walks through the same calls end-to-end.