Call.Report
GitHub
GitHub

ffiec-data-connect (Python)

Incremental updates

Use collect_filers_since_date and collect_filers_submission_date_time to detect new and re-filed submissions without a full re-pull.

Call Report data for a reporting period keeps arriving for weeks — sometimes months — after the quarter-end, as institutions file late or amend previous submissions. A pipeline that does a one-shot pull will be stale within days. This page covers the endpoints designed for keeping an existing dataset current.

Why data changes after submission

See Call Reports § Why submitted data changes. The short version: accounting corrections, regulator inquiries, examination findings, and clarification of regulatory guidance all trigger refilings. Budget for them.

Two detection endpoints

collect_filers_since_date

Returns the RSSDs that filed (or refiled) for a reporting period since a given date. Use it for a “give me everything new since my last run” query.

from ffiec_data_connect import collect_filers_since_date

new_or_changed = collect_filers_since_date(
    creds,
    since_date="4/1/2026",        # your last successful run
    reporting_period="3/31/2026",  # the quarter you care about
)
print(new_or_changed)
# [688556, 175458, 92144, ...]

The return is a list of RSSD integers — just IDs, no timestamps.

collect_filers_submission_date_time

Same filter, plus the submission datetime for each RSSD. Useful when you want to detect late-vs-amended (several submissions per institution per period).

from ffiec_data_connect import collect_filers_submission_date_time

events = collect_filers_submission_date_time(
    creds,
    since_date="4/1/2026",
    reporting_period="3/31/2026",
)
# [{'rssd': 688556, 'datetime': '7/1/2022 12:15:06 AM'}, ...]

FFIEC reports submission timestamps in Washington, DC local time. If you pass date_output_format="python_format", the library returns tz-aware datetime objects already labeled as America/New_York — DST is honored automatically (EST in winter, EDT in summer), so you can compare across quarters or convert to UTC without reattaching anything:

submissions = collect_filers_submission_date_time(
    creds, since_date="1/1/2024", reporting_period="3/31/2026",
    date_output_format="python_format",
)
# submissions[0]["datetime"].tzinfo → zoneinfo.ZoneInfo('America/New_York')
# submissions[0]["datetime"].astimezone(timezone.utc)  # works out of the box

(date_output_format="python_format" was implemented in 3.0.0; prior releases silently ignored the parameter. Output is America/New_York-aware — if you need a different zone, call .astimezone(...) on the result.)

A minimal incremental loop

import json
from pathlib import Path
from datetime import datetime
from ffiec_data_connect import OAuth2Credentials, collect_filers_since_date, collect_data

STATE_FILE = Path("state.json")
PERIOD = "3/31/2026"

def run():
    state = json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
    since = state.get("last_run", "1/1/2026")

    creds = OAuth2Credentials(...)

    new_rssds = collect_filers_since_date(
        creds, since_date=since, reporting_period=PERIOD
    )
    print(f"{len(new_rssds)} institutions with new/amended data since {since}")

    for rssd in new_rssds:
        rows = collect_data(creds, rssd_id=str(rssd), reporting_period=PERIOD,
                            series="call", output_type="list")
        # ... upsert rows into your store ...

    state["last_run"] = datetime.now().strftime("%m/%d/%Y")
    STATE_FILE.write_text(json.dumps(state))

run()

Run this nightly or on whatever cadence your downstream consumers tolerate. After the initial backfill, a typical daily incremental is tens to low-hundreds of institutions — well under the rate limit.

Multi-period monitoring

If you track multiple recent quarters (because any of them can still be refiled), loop the period too:

for period in ["3/31/2026", "12/31/2025", "9/30/2025"]:
    new_rssds = collect_filers_since_date(creds, since_date=since, reporting_period=period)
    for rssd in new_rssds:
        # ... refresh this institution for this period ...

Practically, refilings beyond four quarters back are rare. A three- or four-quarter sliding window is usually sufficient.

UBPR incrementals

UBPR has no equivalent “filers since date” endpoint. Instead, UBPR is regenerated when the underlying Call Report is refiled — so if you’re tracking UBPR, trigger a UBPR re-pull whenever you detect a Call Report refile for the same RSSD+period.

See also

navigate · open · Esc close