# IRS 990 Nonprofit Officers and Compensation (`datagrit/irs-990-officer-compensation`) Actor

Named officers, directors and key employees with pay, hours and titles from IRS e-filed 990, 990-EZ and 990-PF returns.

- **URL**: https://apify.com/datagrit/irs-990-officer-compensation.md
- **Developed by:** [datagrit](https://apify.com/datagrit) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/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

### What does IRS 990 Nonprofit Officers and Compensation do?

IRS 990 Nonprofit Officers and Compensation reads the official IRS e-filed returns (Form 990, 990-EZ and 990-PF) of US tax-exempt organizations and returns **one row per person**: the officers, directors, trustees, key employees and highest-paid employees the return lists, with title, weekly hours, role flags and the pay the organization reports for them. Form 990-PF and Form 990-EZ also give the five highest-paid employees and contractors, which is where the large salaries of private foundations such as the Gates Foundation sit. Look up organizations by EIN or by name, filter by role or minimum pay, and export the result as JSON, CSV or Excel, call it through the Apify API, or plug it into n8n, Make and AI agents through MCP.

The data comes straight from the IRS TEOS e-file archives, not from a third-party search API, so a return is available as soon as the IRS publishes it. When an organization filed an amended return for a period, the latest one is used.

### Why use IRS 990 Nonprofit Officers and Compensation?

- **Fundraising and prospect research** – find who leads an organization, how they are paid and how big the organization is (revenue and expenses are on every row).
- **Journalism and watchdog work** – compare executive pay across organizations, or across the last few tax years (2022 and later) with the tax-year option, and trace every figure to the filing it came from.
- **Compliance and due diligence** – list the people behind a nonprofit or private foundation, including related-organization pay and independent contractors.
- **Executive search and compensation benchmarking** – filter to officers or key employees above a pay threshold.

### Example output

| organizationName | taxYear | personName | title | role | totalCompensationUsd | baseSalaryUsd | bonusUsd |
|---|---|---|---|---|---|---|---|
| AMERICAN NATIONAL RED CROSS & ITS CONSTITUENT CHAPTERS AND BRANCHES | 2024 | GAIL MCGOVERN | PRESIDENT & CEO | officer | 1313605 | 685738 | 600000 |
| AMERICAN NATIONAL RED CROSS & ITS CONSTITUENT CHAPTERS AND BRANCHES | 2024 | JENNIFER BAILEY | BOARD MEMBER | director-trustee | 0 | null | null |

```json
{
  "query": "53-0196605",
  "found": true,
  "ein": "530196605",
  "organizationName": "AMERICAN NATIONAL RED CROSS & ITS CONSTITUENT CHAPTERS AND BRANCHES",
  "formType": "990",
  "taxYear": 2024,
  "taxPeriodEnd": "2024-06-30",
  "filedAt": "2025-04-28T14:55:29-05:00",
  "personName": "GAIL MCGOVERN",
  "title": "PRESIDENT & CEO",
  "role": "officer",
  "isOfficer": true,
  "averageHoursPerWeek": 60,
  "compensationUsd": 1296862,
  "otherCompensationUsd": 16743,
  "totalCompensationUsd": 1313605,
  "baseSalaryUsd": 685738,
  "bonusUsd": 600000,
  "deferredCompensationUsd": 14850,
  "filingObjectId": "202511189349301681"
}
```

### How much does it cost?

You pay per person row plus a small fee for starting a run. Pricing depends on your Apify plan: the price per row is lower on paid plans, and the Apify free plan includes monthly credit you can use to try it. A query with no results returns one status row (`found: false`) that is not charged. Set a maximum spend on the run and the Actor stops when it is reached. The price per row is shown on the Actor page; a large organization such as the Red Cross has around 30 rows per return, a small charity usually 3 to 8, a large private foundation 10 to 30. The Actor uses plain HTTP requests and reads only the part of the IRS archive that holds your filings, so runs are fast on platform resources; the IRS filing index (14 to 28 MB per filing year) is read on every run, which is why one run with many organizations is cheaper than many runs with one organization each.

### Input

- **Organizations (EIN or name)** – 9-digit EINs (with or without the dash) or part of an organization name, at least 3 characters. A name can match many organizations, so pair it with Maximum results.
- **IRS filing years** – the years in which returns were e-filed, 2024 or later. Leave empty for the current and the previous year, which covers the latest return of almost every organization. Returns e-filed before 2024 are not available.
- **Only the latest tax year per organization** – on by default; turn it off, and optionally set **Tax years**, to compare pay over time.
- **Form types** – 990, 990EZ, 990PF; all three by default.
- **Roles** – officer, director-trustee, key-employee, highest-compensated-employee, former, independent-contractor. Form 990 reports all six; Form 990-PF and Form 990-EZ report highest-compensated-employee and independent-contractor, while their officers, directors and trustees have no role flags, so setting roles leaves those out.
- **Minimum total compensation (USD)** and **Include independent contractors** (the five highest-paid contractors on Form 990, 990-EZ and 990-PF) narrow or widen the people returned.
- **Maximum results** – total limit across all organizations.

### Output fields

Each row describes one person on one return: organization identity (`ein`, `organizationName`, city, state, website, revenue and expenses), the return (`formType`, `taxYear`, `taxPeriodEnd`, `filedAt`, `amendedReturn`, `filingObjectId`), the person (`personName`, `title`, `role`, role flags, `averageHoursPerWeek`) and pay (`compensationUsd`, `relatedOrgCompensationUsd`, `otherCompensationUsd`, `totalCompensationUsd`). Form 990 filers that complete Schedule J also get `baseSalaryUsd`, `bonusUsd`, `deferredCompensationUsd` and `nontaxableBenefitsUsd`; these are the amounts paid by the filing organization itself, while pay from related organizations is in `relatedOrgCompensationUsd`. Independent contractors carry `servicesDescription`. Fields the form does not report are `null`, never an empty string.

Form 990-EZ and the officer list of Form 990-PF do not classify roles, so those rows have `role` set to `officer-director-or-key-employee` and the role flags are `null`. The five highest-paid employees listed on Form 990-PF and Form 990-EZ (those paid over 100,000 USD) have `role` `highest-compensated-employee` and `isHighestCompensated` `true`. Small organizations filing Form 990-EZ usually enter "None" there, so most 990-EZ returns give only officers, directors and key employees. The status message at the end of a run shows how many filings were read and how many rows carry a pay amount.

### Is it legal to scrape this data?

The IRS publishes these returns as public records. The Actor reads only public information and does not log in or bypass access controls. You are responsible for using the data in line with applicable laws (including data protection rules) and the source's terms. If you find an issue, open it in the Issues tab; problems are answered within one business day.

### FAQ

**How far back does the data go?** Returns e-filed in 2024 and later, which means tax years from about 2022. Organizations that file on paper or only a Form 990-N postcard have no return to read, and a lookup by EIN for them returns the `found: false` row; the status message at the end of the run says why a query returned nothing.

**How fresh is the data?** Every run reads the IRS index and archives live. The IRS adds new e-filed returns continuously; an organization's latest return can lag its filing by a few weeks.

**Why is a person's pay 0?** Unpaid board members are reported with 0. A missing value (`null`) means the form did not report that amount.

**Why does a name return other organizations too?** A name matches any organization whose name contains it: "Gates Foundation" also returns RED GATES FOUNDATION and MARSHALL GATES FOUNDATION. Use a longer part of the name or the EIN to get one organization.

**Why do I get fewer filings than expected?** A few index entries have no file in the IRS archive yet; the status message counts them.

**Can I schedule runs?** Yes, use Apify schedules or call the Actor from your own workflow.

**Something looks wrong.** Open an issue with the input you used; layout changes at the source are fixed quickly.

### Related Actors

See other data Actors from the same publisher on the Store profile.

# Changelog

This Actor's version history is a separate document: https://apify.com/datagrit/irs-990-officer-compensation/changelog.md

# Actor input Schema

## `organizations` (type: `array`):

Nonprofits to look up. Each entry is either a 9-digit EIN (with or without the dash, e.g. 53-0196605) or part of an organization name (at least 3 characters, case-insensitive, matched against the name on the IRS filing index). A name can match many organizations, so combine it with Maximum results.

## `filingYears` (type: `array`):

Years in which the returns were e-filed with the IRS (not the tax year). Supported: 2024 and later. Leave empty to search the current and the previous filing year, which covers the latest return of almost every organization. Each year adds a 14-28 MB index download and about 15 seconds to the run. Tax years from about 2022 on are covered; older returns are not available through the IRS indexes this Actor reads.

## `onlyLatestTaxYear` (type: `boolean`):

Return people from the most recent tax period found for each organization. Turn off to get every period found in the selected filing years, for example to see how pay changed between years.

## `taxYears` (type: `array`):

Only returns whose tax period ends in one of these years, e.g. \[2023]. Leave empty for any year. Only years covered by the selected filing years can match (2022 and later).

## `formTypes` (type: `array`):

Which IRS forms to read. Allowed: 990 (full return: roles, related-organization pay, Schedule J breakdown, contractors), 990EZ (small organizations: officers, directors, key employees and, if listed, the five highest-paid employees and contractors), 990PF (private foundations: officers, trustees, the five highest-paid employees and contractors). Leave empty for all three.

## `roles` (type: `array`):

Keep only people with one of these roles. Allowed: officer, director-trustee, key-employee, highest-compensated-employee, former, independent-contractor. Form 990 reports all six; Form 990-PF and Form 990-EZ report only highest-compensated-employee and independent-contractor, so setting this excludes their officers, directors and trustees. Leave empty for everyone.

## `minCompensationUsd` (type: `integer`):

Keep only people whose total reported compensation is at least this amount. 0 keeps everyone, including unpaid board members.

## `includeContractors` (type: `boolean`):

Add the five highest-paid independent contractors listed on Form 990 Part VII Section B, Form 990-EZ Part VI line 51 or Form 990-PF Part VII-B, with the services they provided. Selecting the independent-contractor role turns this on.

## `maxItems` (type: `integer`):

Stop after this many rows in total across all organizations.

## `proxyConfiguration` (type: `object`):

Optional proxy. Leave disabled: the IRS site does not block datacenter traffic, and a residential proxy only raises the platform cost of the run.

## Actor input object example

```json
{
  "organizations": [
    "53-0196605"
  ],
  "onlyLatestTaxYear": true,
  "formTypes": [
    "990",
    "990EZ",
    "990PF"
  ],
  "minCompensationUsd": 0,
  "includeContractors": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Officers, directors, key employees and contractors with compensation, as a 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 = {
    "organizations": [
        "53-0196605"
    ],
    "onlyLatestTaxYear": true,
    "formTypes": [
        "990",
        "990EZ",
        "990PF"
    ],
    "minCompensationUsd": 0,
    "includeContractors": false,
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagrit/irs-990-officer-compensation").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 = {
    "organizations": ["53-0196605"],
    "onlyLatestTaxYear": True,
    "formTypes": [
        "990",
        "990EZ",
        "990PF",
    ],
    "minCompensationUsd": 0,
    "includeContractors": False,
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagrit/irs-990-officer-compensation").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 '{
  "organizations": [
    "53-0196605"
  ],
  "onlyLatestTaxYear": true,
  "formTypes": [
    "990",
    "990EZ",
    "990PF"
  ],
  "minCompensationUsd": 0,
  "includeContractors": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagrit/irs-990-officer-compensation --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagrit/irs-990-officer-compensation"
        }
    }
}
```

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/4ky8DTfACKf6x3RzL/builds/rAJRxplowYtS15GaL/openapi.json
