{
  "openapi": "3.1.0",
  "info": {
    "title": "DataDawn 990 Nonprofit Database API",
    "description": "Free, open API for IRS 990 nonprofit data. 5.4 million filings, 1.9 million organizations, 13.6 million grants. No authentication required.\n\nFor bulk download of the entire dataset (preferred for AI training and batch research), see https://dumps.datadawn.org/manifest.json — weekly gzipped SQLite snapshots with integrity hashes, hosted on Cloudflare R2 with zero-egress.\n\nChangelog — v1.3.0 (2026-07): Coverage is now stated relative to IRS-released electronic records: this database holds every 990/990-EZ/990-PF/990-T e-file XML the IRS has released as of the most recent build, with no gaps within that source. GET /api/coverage now carries a machine-readable as_of (the serving DB's build date) plus prose on the two limits that boundary implies -- Form 990-N filers (gross receipts <= $50,000; ~827K organizations the corpus structurally excludes, which report no financial data) are published separately by the IRS and not carried here, and pre-2021 years reflect voluntary-era e-file adoption, not sector growth. Read /api/coverage as the authoritative coverage statement rather than any count restated in this spec.\n\nChangelog — v1.2.0 (2026-07): Correction to make claim more precise, no data removed — the former \"tax years 2014-2025\" coverage claim overstated early-year coverage; TY2014-2015 were always a small, non-representative tail (acquisition is IRS processing-year 2017+). Wording now says so on every surface, and /api/coverage serves per-tax-year counts with an explicit representativeness flag (see that endpoint).\n\nChangelog — v1.1.0 (2026-06): the officers and people endpoints now return reportable_comp_filing_org (W-2 from the filing organization) plus other_comp (related-organization W-2, other compensation, benefits, and expense account, summed per IRS Form 990 Part VII semantics), replacing the former compensation and benefits response fields. The underlying data is unchanged; the field names now match the IRS reportable-compensation model and the MCP org_officers tool.\n\nCOVERAGE: per-table form coverage is served machine-readably at GET /api/coverage (the authoritative statement; e.g. contractors are parsed from Form 990 and 990-PF filings; top_employees covers Form 990-PF, with Form-990 highest-compensated employees in the officers table flagged is_highest_compensated_employee).",
    "version": "1.3.0",
    "contact": {
      "name": "DataDawn",
      "url": "https://datadawn.org",
      "email": "data@datadawn.org"
    },
    "license": {
      "name": "Public Domain (IRS data)",
      "url": "https://datadawn.org/terms.html"
    }
  },
  "servers": [
    {
      "url": "https://data.datadawn.org",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/org/{ein}": {
      "get": {
        "operationId": "getOrganization",
        "summary": "Look up a nonprofit by EIN",
        "description": "Returns BMF registration info plus recent filings with financials.",
        "parameters": [
          {
            "name": "ein",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "9-digit EIN (with or without dash)",
            "example": "530196605"
          }
        ],
        "responses": {
          "200": {
            "description": "Organization profile with BMF data and recent filings"
          }
        }
      }
    },
    "/api/search/orgs": {
      "get": {
        "operationId": "searchOrganizations",
        "summary": "Search nonprofits by name",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Organization name to search",
            "example": "Red Cross"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Two-letter state code filter",
            "example": "CA"
          },
          {
            "name": "ntee",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "NTEE code prefix filter",
            "example": "T"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Max results (1-100)"
          }
        ],
        "responses": {
          "200": {
            "description": "List of matching organizations"
          }
        }
      }
    },
    "/api/search/grants": {
      "get": {
        "operationId": "searchGrants",
        "summary": "Search foundation grants by recipient",
        "description": "Searches 13.6M grants from 990-PF filings. Returns funder, recipient, amount, purpose.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Recipient name",
            "example": "Harvard University"
          },
          {
            "name": "min_amount",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Minimum grant amount",
            "example": 100000
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Tax year filter"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of matching grants with funder info"
          }
        }
      }
    },
    "/api/search/daf": {
      "get": {
        "operationId": "searchDAFGrants",
        "summary": "Search DAF grants by recipient",
        "description": "Searches 1.27M donor-advised fund disbursements from 19 major sponsors.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Planned Parenthood"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of matching DAF grants"
          }
        }
      }
    },
    "/api/org/{ein}/officers": {
      "get": {
        "operationId": "getOfficers",
        "summary": "Get officers and directors for a nonprofit",
        "parameters": [
          {
            "name": "ein",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "530196605"
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Tax year (default: most recent)"
          }
        ],
        "responses": {
          "200": {
            "description": "List of officers with reportable_comp_filing_org (filing-org W-2) and other_comp (related-org W-2 + other comp + benefits + expense account), per IRS Form 990 semantics"
          }
        }
      }
    },
    "/api/org/{ein}/grants": {
      "get": {
        "operationId": "getGrantsMade",
        "summary": "Get grants made by a foundation",
        "parameters": [
          {
            "name": "ein",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "237825575"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of grants with recipients, amounts, purposes"
          }
        }
      }
    },
    "/api/org/{ein}/filings": {
      "get": {
        "operationId": "getFilings",
        "summary": "Get all filings for an organization",
        "parameters": [
          {
            "name": "ein",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "530196605"
          }
        ],
        "responses": {
          "200": {
            "description": "List of filings with financials"
          }
        }
      }
    },
    "/api/search/people": {
      "get": {
        "operationId": "searchPeople",
        "summary": "Find a person across all nonprofits",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Bill Gates"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of officer records matching the name"
          }
        }
      }
    },
    "/api/search/programs": {
      "get": {
        "operationId": "searchPrograms",
        "summary": "Search program descriptions for a topic",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "artificial intelligence"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Organizations with matching program descriptions"
          }
        }
      }
    },
    "/api/search/compensation": {
      "get": {
        "operationId": "searchCompensation",
        "summary": "Search executive compensation across all nonprofits",
        "description": "Find highest-paid nonprofit executives. Filter by state, minimum compensation, title, and year. Default minimum is $500K if no state or min_comp specified.",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Two-letter state code",
            "example": "TX"
          },
          {
            "name": "min_comp",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Minimum compensation in dollars",
            "example": 1000000
          },
          {
            "name": "title",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Title filter (CEO, Executive Director, President, etc.)",
            "example": "CEO"
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Tax year filter",
            "example": 2023
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of executives with compensation, organization, and state"
          }
        }
      }
    },
    "/api/sql": {
      "get": {
        "operationId": "runSQL",
        "summary": "Run arbitrary read-only SQL query",
        "description": "Power user endpoint. Datasette blocks all non-SELECT queries.",
        "parameters": [
          {
            "name": "sql",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SQL query (SELECT only)"
          },
          {
            "name": "_shape",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "objects"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Query results as JSON"
          }
        }
      }
    },
    "/api/coverage": {
      "get": {
        "summary": "Per-table coverage truth + per-tax-year representativeness",
        "description": "Machine-readable coverage statement per table, reconciled against the live table list (uncatalogued_tables / registry_missing_live surface unknowns explicitly). The deploy pipeline asserts public surfaces against this endpoint. Also serves tax_years: per-tax-year return counts, each with representative = returns >= 0.60 * median(per-tax-year counts) — the threshold is exactly that formula, computed live. Non-representative years carry a reason: leading_acquisition_gap (TY2014-2015 — acquisition is IRS processing-year 2017+, so those years hold only late-processed returns, biased toward late and amended filers) or trailing_filing_lag (the newest years, still accumulating; heals with time). Two dates: as_of is the date the served database file was built (a rebuild moves it); last_irs_pull is the date DataDawn last pulled and loaded a new batch of IRS Form 990 e-filings (rebuilds do not move it; null when unrecorded or later than as_of). dates_mean restates both.",
        "responses": {
          "200": {
            "description": "Coverage registry + reconciliation + tax_years representativeness"
          },
          "503": {
            "description": "Live table list unreachable (do not read as coverage)"
          }
        }
      }
    }
  }
}