# US Nonprofit Search — IRS Form 990 Financials (`dalbian/nonprofit-990-financials`) Actor

Search 1.8 million US tax-exempt organisations by name, state, cause area and 501(c) subsection, then pull the Form 990 financials the IRS holds for each one: revenue, expenses, assets, liabilities, contributions, officer pay, year by year. Free IRS data through ProPublica Nonprofit.

- **URL**: https://apify.com/dalbian/nonprofit-990-financials.md
- **Developed by:** [Benjamin Jerez](https://apify.com/dalbian) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 search runs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## US Nonprofit Search — IRS Form 990 Financials

Search 1.8 million US tax-exempt organisations by name, state, cause area and 501(c) subsection, then pull the Form 990 financials the IRS publishes for each one — revenue, expenses, assets, liabilities, contributions, officer compensation — for the latest year or for every year on file.

The data is the IRS's own. It reaches you through **ProPublica Nonprofit Explorer**, which is free and needs no key.

### What one organisation looks like

EIN `53-0196605`, American National Red Cross, fiscal year ending June 2023:

| Field | Value |
| --- | --- |
| `name`, `city`, `state` | American National Red Cross · Washington · DC |
| `nteeCode`, `category` | P210 · Human services |
| `subsection`, `rulingDate` | 501(c)(3) charity · 1938-12-01 |
| `latestFiscalYear`, `formType` | 2023 · 990 |
| `totalRevenue` | 3,217,077,611 |
| `totalExpenses` | 2,971,106,889 |
| `surplus` | 245,970,722 |
| `totalAssets` | 4,028,321,133 |
| `totalLiabilities` | 1,008,326,202 |
| `netAssets` | 3,019,994,931 |
| `contributions` | 919,126,379 |
| `programRevenue` | 2,167,924,872 |
| `filingsWithFinancials`, `filingsPdfOnly` | 13 · 11 |
| `propublicaUrl` | projects.propublica.org/nonprofits/organizations/530196605 |
| `irsPdfUrl` | the scanned 990 those figures came from |

Those seven money figures cross-check exactly against the Form 990 the Red Cross publishes itself at redcross.org. Nothing here is estimated or modelled; it is the filed return.

Turn on **Include one row per filing year** and you also get a `filing` row for each year, linked by `ein`, carrying about thirty line items — investment income, royalties, gross rents, net gain on asset sales, fundraising gross income and direct expenses, gaming income, membership dues, officer compensation, other salaries and wages, payroll taxes, professional fundraising fees, tax-exempt bonds, secured mortgages, unsecured notes. Red Cross revenue reads 3,217,077,611 for 2023, 3,182,229,338 for 2022 and 3,090,183,560 for 2021.

### Searching

Four filters, combinable:

- **Search terms** — one per line. Each line is a separate search with its own `summary` row.
- **State** — two-letter abbreviation, the state the organisation files from.
- **Cause area** — the ten NTEE major groups.
- **Tax-exempt subsection** — 501(c)(3), 501(c)(4), and so on.

`humane society` + Wyoming + Environment and animals + 501(c)(3) matched 8 organisations. Adding a minimum revenue of 250,000 left two: Casper Humane Society at 1,034,354 and Red Desert Humane Society at 377,846.

Leave the search terms empty and the filters alone become a browse. Vermont + Arts, culture and humanities + 501(c)(3) returns 782 registered organisations, no keyword needed.

Or skip searching and put EINs straight in. `53-0196605` and `530196605` are both accepted.

### How long a run takes

Every search result costs a second request. The search index is thin — it carries a name, a city and an NTEE code and no money at all — so the financials come from a per-organisation lookup. There is no bulk endpoint.

In practice that is fast. A 300-organisation run over `animal rescue` in Texas took **12.5 seconds** end to end with four requests in flight. A thousand organisations takes under a minute. But the cost is linear in results, so `maxResultsPerSearch` is the setting that decides your run time.

### Not every organisation has financials

This matters more than anything else in the output. Of those 299 Texas animal-rescue organisations, **205 had no financial figures at all** — a valid IRS registration, an EIN, an address, and nothing else.

They are not missing. Organisations under 50,000 dollars of gross receipts file the 990-N e-Postcard, which asks for no numbers, so there is nothing to publish. Broad searches over small local charities will be mostly registrations. Narrow searches over hospitals, universities and foundations will be mostly complete. The `summary` row reports `withoutFinancials` for each search so you know which kind of result you have before you open the file.

Set a **minimum total revenue** to drop them, and anything else below your threshold, in one step.

### Three different forms

An organisation files a 990, a 990-EZ or a 990-PF depending on its size and type, and the three forms are not the same document. A full 990 carries 68 fields, a 990-EZ 47, a 990-PF 126 — and they use different names for the same thing. Net assets is `totnetassetend` on a 990, `totnetassetsend` on a 990-EZ and `tfundnworth` on a 990-PF.

The Actor normalises all three onto one set of field names, so `totalRevenue` means total revenue whatever was filed. Where a form genuinely does not collect something the field is simply absent rather than zero: a 990-PF has no program service revenue line, so private foundations have no `programRevenue`.

Organisations also switch forms between years. Castleton Free Library in Vermont filed a 990-EZ from 2011 to 2022 reporting 187,679 in revenue, then a full 990 for 2023 reporting 613,042. Both years are in the output with `formType` saying which is which.

Private foundations get their own fields where the form provides them: the Gates Foundation's 2023 990-PF returns 7,810,137,842 in revenue, 76,951,451,400 in assets and 7,200,556,970 in `grantsPaid`.

### Who uses this

Grantmakers and foundations screening prospective grantees, and checking a nonprofit's finances before a cheque goes out. Fundraising and development teams building prospect lists by cause and geography. Journalists and researchers tracking where charitable money goes. Due-diligence and compliance teams verifying that a counterparty is a real 501(c)(3) in good standing. Nonprofit consultants benchmarking a client against comparable organisations in the same state and cause area. Anyone building a charity directory who would rather not scrape one.

### Scope and limits

**The most recent year with figures is usually one to two years back.** The IRS releases machine-readable extracts long after the return is filed. The Red Cross had its FY2024 return available as a scanned PDF while FY2023 was still the newest with extracted numbers. When that happens the Actor reports it as `newerPdfOnlyYear` and `newerPdfOnlyUrl` rather than quietly looking out of date.

**A 990 is not audited financial statements.** It is a tax return, filed on the organisation's own fiscal year, using the IRS's definitions. It will not always agree with the consolidated statements in an annual report, and a fiscal year ending in June is labelled by the year it ends in.

**State means the state of registration.** A national organisation headquartered in Washington DC files from DC regardless of where its programmes run.

**A search reaches 10,000 results.** The search backend stops counting and paging there. Narrow by state or cause area to get past it; the `summary` row sets `matchesCapped` when you have hit the ceiling.

**Chapters and affiliates file separately.** Searching for a well-known national charity returns the national entity and its separately incorporated local affiliates as distinct EINs, because that is how they file.

### Output

Three row types in one dataset, distinguished by `rowType`:

- **`summary`** — one per search, pushed first, carrying the query, the filters applied, `totalMatches`, how many were inspected, how many were returned, how many fell below your revenue floor and how many had no financials.
- **`organization`** — one flat row per organisation, with the latest year's headline financials folded in.
- **`filing`** — one row per fiscal year, linked to its organisation by `ein`, only when you ask for them.

### Source and licence

**ProPublica Nonprofit Explorer API**, `projects.propublica.org/nonprofits/api`. The underlying data is the IRS Exempt Organizations Business Master File and the IRS annual extracts of Form 990 financial data, both US federal government works in the public domain. ProPublica's terms ask that the data be credited; the Actor puts ProPublica's own `data_source` string on every organisation row so the extract date travels with the data.

Queried live on every run. No key, no account.

### Frequently asked

**Why is `totalRevenue` empty for so many results?**
Because those organisations file the 990-N e-Postcard, which collects no figures. See "Not every organisation has financials" above. Set a minimum revenue to exclude them.

**Why is the latest year 2023 and not last year?**
The IRS publishes machine-readable extracts well after returns are filed, and ProPublica publishes what the IRS gives it. Where a newer return exists as a scan only, `newerPdfOnlyYear` tells you so and `newerPdfOnlyUrl` links the PDF.

**What is an EIN that returns nothing?**
An EIN not in the Business Master File. The row comes back with `found: false` and an explanation rather than being dropped, so a list of EINs comes back the same length it went in. In a 300-result Texas search, exactly one hit had no master-file record behind it.

**Can I get the full Form 990, not just the totals?**
Not as data. The Actor returns the extracted financial line items plus `irsPdfUrl` for the scanned return and `fullFilingUrl` for ProPublica's rendered version of the complete filing, including the schedules and the officer compensation table.

**Does `netAssets` mean the same on every form?**
Yes as a concept, and the Actor maps all three forms onto it. It is end-of-year net assets or fund balances, which for a private foundation is reported as total fund net worth.

**Do I get charged for an organisation with no financials?**
Yes — it is still a returned organisation with a verified registration, address, NTEE classification and exempt status, which is often exactly what a due-diligence check needs. Set a minimum revenue if you only want filers.

# Actor input Schema

## `searchTerms` (type: `array`):

One search per line — an organisation name, a cause, a city. 'food bank', 'humane society', 'community foundation'. Leave this empty and set a state or a cause area below to browse everything registered there instead of searching for words.

## `eins` (type: `array`):

Employer Identification Numbers to look up directly, one per line. Either form works: 53-0196605 or 530196605. Use this when you already know the organisation and want its filings rather than a search.

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

Two-letter US Postal Service abbreviation — VT, CA, NY. The state on the IRS registration, which is where the organisation files, not necessarily where it operates.

## `nteeCategory` (type: `string`):

NTEE major group, the IRS classification of what the organisation does. Human services is the largest group by far and covers food, housing, youth and emergency relief.

## `subsectionCode` (type: `string`):

Which part of section 501(c) the organisation is exempt under. 501(c)(3) is the one donations are deductible against; 501(c)(4) is the advocacy category where they are not.

## `minRevenue` (type: `integer`):

Drop organisations whose most recent filing reports less total revenue than this, in US dollars. Applied after the filing is fetched, so it filters the output rather than the search. Organisations with no filed financials at all are dropped when this is set.

## `includeFilings` (type: `boolean`):

Add a separate row for every year of financials, not just the latest. This is what you want for a trend — most organisations have ten to thirteen years on file. Off by default because it multiplies the row count.

## `maxFilingsPerOrg` (type: `integer`):

Cap on filing rows per organisation, most recent year first.

## `maxResultsPerSearch` (type: `integer`):

How many organisations to return for each search term. Every result costs one extra request because the search itself carries no financials, so this is the setting that drives run time. The API stops at 10 000 results per query.

## Actor input object example

```json
{
  "searchTerms": [
    "food bank"
  ],
  "includeFilings": false,
  "maxFilingsPerOrg": 10,
  "maxResultsPerSearch": 50
}
```

# Actor output Schema

# 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 = {
    "searchTerms": [
        "food bank"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dalbian/nonprofit-990-financials").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 = { "searchTerms": ["food bank"] }

# Run the Actor and wait for it to finish
run = client.actor("dalbian/nonprofit-990-financials").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "food bank"
  ]
}' |
apify call dalbian/nonprofit-990-financials --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dalbian/nonprofit-990-financials"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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