# Bank & Credit-Union Financial Health API — FDIC/NCUA QoQ (`malonestar/fdic-ncua-health-rollup`) Actor

Bank & credit-union financial-health API on keyless FDIC data (NCUA v1.1): unified per-institution assets, deposits, equity, ROA, ROE, NIM and asset quality, with quarter-over-quarter deltas, peer-percentile scoring, and derived health flags (deposit outflow, low ROA, rising NPL).

- **URL**: https://apify.com/malonestar/fdic-ncua-health-rollup.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Lead generation, Developer tools, Agents
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.40 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Bank & Credit-Union Financial Health API — FDIC Capital, Uninsured Deposits & CRE

A **bank financial-health API** that turns raw regulatory call-report data into a
decision-ready screen. It pulls US **FDIC-insured banks** into one normalized schema
and ships the analytics layer on top: **regulatory capital ratios with a PCA
category**, the **post-2023 stress screen** (uninsured deposit ratio, AFS unrealized
losses, CRE concentration), credit quality, efficiency, **quarter-over-quarter deltas**,
**peer-percentile scoring**, and **derived health flags at the supervisory thresholds**.

The underlying numbers are free and public. What they are not is joined, derived, or
screened — and three of the four metrics regulators and rating agencies actually used
in 2023 don't exist as fields at all. This actor computes them.

### Who it's for

- **Corporate treasury & commercial lenders** running bank counterparty risk. CDS
  spreads and share prices don't exist for ~4,300 private community banks; call-report
  data is the only signal there is.
- **Bank & credit-union strategy / correspondent teams** benchmarking against a peer band.
- **Fintech & BaaS partnership teams** screening sponsor-bank health before signing.
- **Bank M\&A advisors, investors and analysts** building peer comps by state or asset band.
- **Deposit brokers & treasury desks** watching quarter-over-quarter deposit flows.
- **AI agents** needing a clean, chainable "bank financial health" lookup and scoring tool.

### The stress screen

After SVB, Signature and First Republic, four metrics became the standard screen. Three
of them are **not published fields** — they have to be derived from the call report:

| Metric | How it's derived | Flagged at |
|---|---|---|
| **Uninsured deposit ratio** | uninsured ÷ total deposits | **> 50%** (OFR cutoff; SVB was 92.5%) |
| **AFS unrealized loss / equity** | fair value − amortized cost, against equity. **The FDIC publishes no AOCI or unrealized-loss field.** | **> 100%** of equity (the OFR cutoff that identified 185 banks) |
| **CRE / Tier 1 capital** | nonfarm-nonresidential + multifamily + construction ÷ Tier 1. **There is no single "CRE" field.** | **≥ 300%** — and **≥ 100%** for construction alone (2006 interagency guidance) |
| **QoQ deposit change** | current vs prior quarter | **≤ −2%** |

Banks tripping both prongs of the 2006 CRE guidance historically failed at **22.9%**,
versus 0.5% for banks tripping neither.

Plus a **PCA capital category** (`well_capitalized` / `adequately_capitalized` /
`undercapitalized` / `significantly_undercapitalized`) derived from all four regulatory
ratios per 12 CFR 324.403. It returns `null` rather than guessing when any input ratio
is missing.

**v1.3 evaluates the CRE guidance properly.** The 2006 test is two prongs, and the
second needs 12 quarters of history that no single call-report row carries:

> Construction ≥ **100%** of capital — **OR** — CRE ≥ **300%** of capital **AND** CRE
> grew ≥ **50%** over 36 months.

Through v1.2 only the level halves were checked, which over-flagged banks holding a
large but *static* CRE book. v1.3 pulls the quarter from 12 quarters back and emits
`cre_growth_36m_pct` and `cre_guidance_prong`, so `cre_guidance_both_prongs` marks the
cohort that actually failed at 22.9%.

### Real peer groups, not "whatever you pulled"

A state cohort mixes a $27M agricultural bank with a $200B trust bank. Ranking them
against each other produces a number, not an insight. `peerBasis` picks the cohort:

| `peerBasis` | Peer group |
|---|---|
| `cohort` | Everything you pulled (the v1.2 behaviour, still the default) |
| `business_line` | FDIC SPECGRP business-model group — the cut a bank examiner uses |
| `asset_band` | FFIEC-style asset-size band |
| `community_bank` | The FDIC community-bank research flag |

Every percentile — assets, ROA, CRE concentration, uninsured deposits — is then computed
*within* that group. A group with fewer than 5 institutions falls back to the full
cohort instead of ranking a bank against two neighbours.

Set `benchmark` to `national` or `state` and each row also carries the cohort's
**asset-weighted** ratios and this bank's distance from them in percentage points
(`uninsured_vs_benchmark_pts`, `cre_vs_benchmark_pts`, `unrealized_vs_benchmark_pts`).
Asset-weighted, not an average of per-bank ratios, so a $27M bank can't outvote a $200B
one. It costs **one** extra request — the FDIC API aggregates server-side, so the
national benchmark across all ~4,350 banks arrives in a single call rather than a
4,350-row download.

### Modes

Every mode returns the **same full field set**. Mode changes the ordering only.

- **snapshot** — largest institutions first.
- **delta** — biggest quarter-over-quarter deposit move first (the run-risk view).
- **score** — highest peer asset percentile first (the peer-comp view).
- **stress** — most health flags first (the triage view).

### Example input

```json
{
  "state": "CA",
  "institutionType": "bank",
  "mode": "stress",
  "minAssets": 250000,
  "maxAssets": 0,
  "maxResults": 500
}
```

FDIC reports assets in **$000s**, so `minAssets: 250000` = $250M. Set `state` for a
focused run and state-level peer scoring.

### Output (per institution)

**Identity & core** — `institution_type`, `id`, `id_scheme`, `name`, `city`, `state`,
`total_assets`, `total_deposits`, `equity`, `roa`, `roe`, `net_interest_margin`,
`asset_quality_ratio`, `report_date`

**Quarter-over-quarter** — `prior_report_date`, `prior_period_assets`,
`prior_period_deposits`, `qoq_asset_change_pct`, `qoq_deposit_change_pct`

**Peer scoring** — `peer_asset_percentile`, `peer_roa_percentile`

**Capital adequacy** — `leverage_ratio`, `cet1_ratio`, `tier1_rbc_ratio`,
`total_rbc_ratio`, `tier1_capital`, `capital_framework`, `pca_capital_category`

**Deposit composition & funding** — `uninsured_deposits`, `insured_deposits`,
`uninsured_deposit_ratio`, `core_deposits_ratio`, `brokered_deposits_ratio`,
`loans_to_deposits_ratio`

**Securities & unrealized losses** — `afs_fair_value`, `afs_amortized_cost`,
`afs_unrealized_gain_loss`, `unrealized_loss_to_equity_pct`, `htm_fair_value`,
`total_securities`

**Loan concentration** — `cre_total_loans`, `cre_to_tier1_pct`, `construction_loans`,
`nonfarm_nonres_loans`, `multifamily_loans`, `ci_loans`, `construction_to_tier1_pct`,
`re_loans_to_tier1_pct`

**Credit quality** — `nonperforming_assets_ratio`, `net_charge_off_ratio`,
`loan_loss_reserve_ratio`, `provision_for_credit_losses`, `earnings_coverage_of_nco`

**Earnings & efficiency** — `efficiency_ratio`, `cost_of_funds_pct`, `pretax_roa`

**Peer cohort & holding company (v1.3)** — `business_line`, `business_line_code`,
`is_community_bank`, `charter_class`, `holding_company`, `holding_company_rssd`,
`peer_basis`, `peer_group`, `peer_group_label`, `peer_group_size`,
`peer_cre_percentile`, `peer_uninsured_percentile`

**CRE 36-month growth (v1.3)** — `cre_total_loans_36m_ago`, `cre_growth_36m_pct`,
`cre_baseline_date`, `cre_guidance_prong`

**Peer benchmark (v1.3)** — `benchmark_scope`, `benchmark_peer_count`,
`benchmark_uninsured_deposit_ratio`, `benchmark_cre_to_tier1_pct`,
`benchmark_unrealized_loss_to_equity_pct`, `uninsured_vs_benchmark_pts`,
`cre_vs_benchmark_pts`, `unrealized_vs_benchmark_pts`

**Tail** — `health_flags[]`, `source_url`, `retrieved_at`

Dollar figures are in **thousands** (FDIC convention). Ratio fields are already percentages.

### Health flags

**Fundamentals:** `deposit_outflow`, `asset_decline`, `low_roa`, `negative_roa`,
`negative_roe`, `elevated_npl`, `rising_npl`, `thin_capital`.

**Stress screen:** `uninsured_over_50pct`, `unrealized_loss_over_100pct_equity`,
`cre_over_300pct_capital`, `construction_over_100pct_capital`, `below_well_capitalized`.

**2006 CRE guidance (v1.3):** `cre_growth_over_50pct_36m`, `cre_guidance_both_prongs`.
The second one is the real test — construction ≥ 100% of capital, or CRE ≥ 300% *and*
+50% growth over 36 months — and marks the cohort that historically failed at 22.9%.

### Honest notes

- **Field coverage was verified on the smallest banks, not just the big ones.** Every
  field here returns non-null across the 40 smallest Texas banks (assets from $17.4M).
  That matters: the obvious-looking CET1 code (`RBCT1CER`) is null for 63% of community
  banks, so this actor uses `IDT1CER` instead.
- **CBLR filers report no risk-based ratios, and the FDIC returns them as zero, not null.** Banks that elect the Community Bank Leverage Ratio framework (12 CFR 324.12, leverage >= 9%) are exempt from reporting CET1 / tier 1 / total RBC. In a live 300-bank Texas cohort, **115 were CBLR filers**. This actor detects them, emits `capital_framework: "cblr"`, nulls the ratios rather than passing zeros through, and treats the election itself as well capitalized — which is what it regulatorily means.
- **The CRE denominator is Tier 1, and the growth prong needs `creGrowth` on.** The
  official 300% test is measured against *total* risk-based capital, which is larger
  than Tier 1, so `cre_to_tier1_pct` runs slightly high and the level flag is
  deliberately **conservative**: it catches every bank the official test would, plus a
  few sitting near the line. The 36-month growth prong (v1.3) is evaluated only when
  `creGrowth` is on; with it off, `cre_guidance_both_prongs` can still fire on the
  construction prong, which needs no history, but the CRE-growth path cannot.
- **`cre_growth_36m_pct` is null for banks that did not exist 12 quarters ago.** A
  de-novo or recently-chartered bank has no baseline quarter, and this actor reports
  that as `null` rather than inventing a 0%. Those banks can trip the construction prong
  but never the growth prong.
- **`uninsured_deposits` is an FDIC estimate.** Banks under $1B in assets don't report
  the underlying schedule item directly, and there was a wave of restatements after the
  FDIC's July 2023 guidance, so pre- and post-restatement ratios aren't comparable.
- **Trust banks report zero deposits.** Ratios with a zero denominator return `null`,
  never `Infinity`.
- **Credit unions aren't live yet.** `institutionType: "credit_union"` **fails the run
  immediately and bills nothing**, rather than quietly handing back bank data. Use
  `"bank"` today, or `"all"` to take the bank half now and pick up credit unions
  automatically the moment v1.3 lands. The NCUA bulk 5300 feed is verified and the
  column mapping is wired; only the parser remains.

### Changelog

**v1.3** — Real peer cohorts, peer benchmarks, and the missing half of the CRE test.
Percentiles can now be computed within an FDIC business-line peer group, an asset-size
band, or the community-bank split, instead of against "whatever you pulled"; groups
under 5 institutions fall back to the cohort rather than ranking a bank against two
neighbours. Added asset-weighted national/state benchmarks and per-row distance from
them in percentage points, using the FDIC's server-side aggregation so the benchmark
across all ~4,350 banks costs one request, not a 4,350-row download. Added the 2006
guidance's 36-month CRE growth prong (`cre_growth_36m_pct`, `cre_guidance_prong`,
`cre_guidance_both_prongs`) — the level-only test in v1.2 over-flagged banks with a
large but static CRE book. Added business line, community-bank flag, charter class and
holding company (via the Fed RSSD; the FDIC's `ULTCERT` turned out to be
self-referential, not a parent pointer, on all 347 Texas banks). **24 new fields, all
appended — every v1.2 field keeps its name and position, and the default `peerBasis`
reproduces v1.2 scoring exactly.**

**v1.2.6** — Fixed a silent-substitution defect: `institutionType: "credit_union"` fell
through to `"bank"`, so the run **succeeded and billed** while returning FDIC banks
tagged `institution_type: "bank"`. An unavailable institution type is now a hard,
zero-cost failure with an explicit message. Wrong data that looks right is worse than
no data, and it should never cost you anything. Type resolution moved into a pure,
unit-tested function with 12 regression assertions covering casing, whitespace, unknown
types, and the `"all"` partial-coverage path.

**v1.2** — `/financials` is now joined in **every** mode. Through v1.1, the default
`snapshot` mode returned seven permanently-null columns (NIM, asset quality, and all
five QoQ fields) because it only called `/institutions`, which doesn't carry them.
Added ~30 capital / funding / securities / loan-concentration / credit-quality fields
and the stress screen. Dropped `NPTLA`, which is not a real FDIC field and was silently
discarded by the API on every request. Detects CBLR filers so their unreported (zero) risk-based ratios are never read as real values. Switched to the canonical `api.fdic.gov` host
(the old one 301-redirected on every call) and added retry with backoff. **All v1.1
field names and positions are unchanged — v1.2 is strictly additive.**

### Use as an MCP tool

Available to AI agents via `mcp.apify.com` as a bank-financial-health tool — pass a
state, type and mode, get normalized, scored, flagged institution records back. The
field-level output descriptions make it cleanly chainable (screen a market, then hand
the flagged institutions to the next step).

### FAQ

**Is it keyless?** Yes — the FDIC BankFind API needs no key. Note that passing an
*invalid* key returns 403, so this actor never sends one.

**Where does the data come from?** Official FDIC institution and quarterly financial
call-report data, via `api.fdic.gov/banks/institutions` and `api.fdic.gov/banks/financials`.

**How current is it?** As of the latest published FDIC quarter-end — see `report_date`
on every row.

**How do I find banks with high uninsured deposits?** Run `mode: "stress"` and filter on
the `uninsured_over_50pct` flag, or sort by `uninsured_deposit_ratio`.

**How do I check CRE concentration against the regulatory threshold?** `cre_to_tier1_pct`
against 300%, and `construction_to_tier1_pct` against 100%.

**Why are the asset figures so large?** FDIC reports assets and deposits in **thousands
of dollars**.

**Can I diff two arbitrary runs?** Yes — pass a prior run's rows as `priorItems`.

**Are credit unions included?** Not yet — see the honest notes above.

### Related actors

| Actor | What it adds |
|---|---|
| [FDIC Deposit Market Share & HHI Rollup](https://apify.com/malonestar/fdic-sod-deposit-market-share-rollup) | Branch-level deposit share, county/MSA rollups, HHI concentration and the market-gap screen |
| [SEC RIA Registration Delta Monitor](https://apify.com/malonestar/ria-registration-delta-monitor) | Investment-adviser registrations, AUM changes and terminations |
| [Bank Enforcement Action Tracker](https://apify.com/malonestar/bank-enforcement-tracker) | Formal regulatory enforcement actions against banks |

### Pricing

Pay per result: you are billed only for the institution-health records actually emitted
(cap with `maxResults`). Empty cohorts cost only the actor start.

# Actor input Schema

## `state` (type: `string`):

US state to scope the cohort, e.g. CA, TX, NY. Strongly recommended: it focuses the run and makes peer percentiles state-level. Empty = the entire country (slower; national peer scoring).

## `institutionType` (type: `string`):

Which institutions to include. 'bank' = FDIC-insured banks, fully supported, the only option that returns data today. 'credit\_union' = NCUA — NOT AVAILABLE YET (ships in v1.3); selecting it alone fails the run immediately and bills nothing, rather than quietly handing back bank data. 'all' = runs the bank half now and picks up credit unions automatically the moment v1.3 lands.

## `mode` (type: `string`):

Every mode returns the SAME full field set — capital ratios, uninsured deposits, unrealized losses, CRE concentration, credit quality and quarter-over-quarter deltas. Mode changes the ordering only. snapshot = largest institutions first. delta = biggest quarter-over-quarter deposit move first (the headline run-risk signal). score = highest peer asset percentile first. stress = most health flags first, the triage view.

## `peerBasis` (type: `string`):

What counts as a 'peer' when computing peer\_asset\_percentile, peer\_roa\_percentile, peer\_cre\_percentile and peer\_uninsured\_percentile. 'cohort' scores against everything you pulled (a state cohort mixes a $27M agricultural bank with a $200B trust bank, so the percentile means little). 'business\_line' uses the FDIC SPECGRP business-model peer group — the cut a bank examiner uses. 'asset\_band' uses FFIEC-style size bands. 'community\_bank' splits on the FDIC community-bank research flag. Groups with fewer than 5 institutions fall back to the full cohort rather than ranking a bank against two neighbours.

## `benchmark` (type: `string`):

Adds asset-weighted benchmark ratios and this bank's distance from them, in percentage points: benchmark\_uninsured\_deposit\_ratio, benchmark\_cre\_to\_tier1\_pct, benchmark\_unrealized\_loss\_to\_equity\_pct plus uninsured\_vs\_benchmark\_pts, cre\_vs\_benchmark\_pts, unrealized\_vs\_benchmark\_pts. 'national' compares against all ~4,350 FDIC-insured banks; 'state' against the banks in your state. Costs exactly ONE extra request thanks to server-side aggregation — not a second full download. 'none' skips it.

## `creGrowth` (type: `boolean`):

The 2006 interagency CRE guidance is TWO tests: construction >= 100% of capital, OR (CRE >= 300% of capital AND CRE grew >= 50% over 36 months). Leaving this on fetches the quarter from 12 quarters ago — one extra request — and fills cre\_growth\_36m\_pct, cre\_total\_loans\_36m\_ago, cre\_baseline\_date and cre\_guidance\_prong, plus the cre\_guidance\_both\_prongs flag. Turn it off to skip that request; the level tests still run.

## `minAssets` (type: `integer`):

Only include institutions with at least this many total assets, in thousands of dollars (FDIC reports assets in $000s, so 1000000 = $1B). Use with maxAssets to build a peer band. 0 = no floor.

## `maxAssets` (type: `integer`):

Only include institutions with at most this many total assets, in thousands of dollars. 0 = no ceiling. Combine with minAssets to score within an asset-size peer band (e.g. community banks $250M–$1B).

## `priorItems` (type: `array`):

Optional. In delta mode, an array of institution rows from a previous run (each needs id, total\_assets, total\_deposits) to diff the current quarter against, instead of auto-fetching the prior quarter. Lets you compare two arbitrary runs.

## `maxResults` (type: `integer`):

Maximum number of institution-health records to return after filtering, scoring, and ranking. This is your cost cap: one record = one billable result. 500 covers a full mid-size state; TX has ~380 banks, CA ~180.

## Actor input object example

```json
{
  "state": "TX",
  "institutionType": "bank",
  "mode": "stress",
  "peerBasis": "business_line",
  "benchmark": "national",
  "creGrowth": true,
  "minAssets": 0,
  "maxAssets": 0,
  "priorItems": [],
  "maxResults": 500
}
```

# Actor output Schema

## `results` (type: `string`):

Unified bank/credit-union financial-health records with QoQ deltas and peer percentiles, in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "state": "TX",
    "institutionType": "bank",
    "mode": "stress",
    "peerBasis": "business_line",
    "benchmark": "national",
    "creGrowth": true,
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/fdic-ncua-health-rollup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "state": "TX",
    "institutionType": "bank",
    "mode": "stress",
    "peerBasis": "business_line",
    "benchmark": "national",
    "creGrowth": True,
    "maxResults": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/fdic-ncua-health-rollup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "state": "TX",
  "institutionType": "bank",
  "mode": "stress",
  "peerBasis": "business_line",
  "benchmark": "national",
  "creGrowth": true,
  "maxResults": 500
}' |
apify call malonestar/fdic-ncua-health-rollup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=malonestar/fdic-ncua-health-rollup",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/WEgRp3QcB0oxwDdlu/builds/rIgwf227nUyjsXYZM/openapi.json
