openapi: 3.2.0 info: title: Plinth Grants API summary: US foundation and nonprofit funding data from public IRS Form 990 and 990-PF filings. description: 'A read API over the US grantmaking universe, read from public IRS Form 990, 990-EZ and 990-PF e-file filings. The funder-grantee graph traverses in BOTH directions: filter by `funder_id` for everything a foundation funded, or by `recip_id` for every funder behind a nonprofit. Start with `/api/search` to turn an organization name into an EIN and a canonical page URL — it needs no key. Every other endpoint requires one (free tier: 50 calls a month). Figures are read directly from named IRS filings. The IRS releases e-file data on a 12-24 month lag, so every figure is dated to its fiscal year rather than to today. Funding relationships are reported as association, never as causation. Organizations that do not e-file may be absent.' version: 1.0.0 contact: name: Plinth url: https://data.useplinth.com/developers license: name: 'Source data: IRS public domain' url: https://www.irs.gov/charities-non-profits/tax-exempt-organization-search-bulk-data-downloads termsOfService: https://www.useplinth.com/terms servers: - url: https://data.useplinth.com description: Plinth US philanthropy data security: - ApiKeyAuth: [] tags: - name: Grants description: 'The funder-grantee graph: grants, funders, recipients and aggregates.' paths: /api/grants/transactions: get: summary: List individual grants operationId: listGrants parameters: - name: funder_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Funder Id - name: recip_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Recip Id - name: year in: query required: false schema: anyOf: - type: string - type: 'null' title: Year - name: subject in: query required: false schema: anyOf: - type: string - type: 'null' title: Subject - name: location in: query required: false schema: anyOf: - type: string - type: 'null' title: Location - name: min_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Min Amt - name: max_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Max Amt - name: page in: query required: false schema: anyOf: - type: string - type: 'null' title: Page - name: limit in: query required: false schema: anyOf: - type: string - type: 'null' title: Limit - name: sort_by in: query required: false schema: anyOf: - type: string - type: 'null' title: Sort By - name: sort_order in: query required: false schema: anyOf: - type: string - type: 'null' title: Sort Order responses: '200': description: Successful Response content: application/json: schema: {} '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' tags: - Grants description: 'Individual grant rows — funder, recipient, amount, fiscal year, cause and the purpose text as filed. The graph traverses both ways: `funder_id` for everything a foundation funded, `recip_id` for every funder behind a nonprofit.' /api/grants/funders: get: summary: Rank funders by giving operationId: listFunders parameters: - name: funder_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Funder Id - name: recip_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Recip Id - name: year in: query required: false schema: anyOf: - type: string - type: 'null' title: Year - name: subject in: query required: false schema: anyOf: - type: string - type: 'null' title: Subject - name: location in: query required: false schema: anyOf: - type: string - type: 'null' title: Location - name: min_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Min Amt - name: max_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Max Amt - name: page in: query required: false schema: anyOf: - type: string - type: 'null' title: Page - name: limit in: query required: false schema: anyOf: - type: string - type: 'null' title: Limit responses: '200': description: Successful Response content: application/json: schema: {} '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' tags: - Grants description: 'Funders matching the filter, ranked by total dollars: amount, grant count, distinct recipients reached, and the first and last fiscal years they were active.' /api/grants/recipients: get: summary: Rank recipients by what they received operationId: listRecipients parameters: - name: funder_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Funder Id - name: recip_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Recip Id - name: year in: query required: false schema: anyOf: - type: string - type: 'null' title: Year - name: subject in: query required: false schema: anyOf: - type: string - type: 'null' title: Subject - name: location in: query required: false schema: anyOf: - type: string - type: 'null' title: Location - name: min_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Min Amt - name: max_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Max Amt - name: page in: query required: false schema: anyOf: - type: string - type: 'null' title: Page - name: limit in: query required: false schema: anyOf: - type: string - type: 'null' title: Limit responses: '200': description: Successful Response content: application/json: schema: {} '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' tags: - Grants description: Recipient organizations matching the filter, ranked by dollars received, with location and how many distinct funders backed them. /api/grants/summary: get: summary: Aggregate totals for a filter operationId: getGrantsSummary parameters: - name: funder_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Funder Id - name: recip_id in: query required: false schema: anyOf: - type: string - type: 'null' title: Recip Id - name: year in: query required: false schema: anyOf: - type: string - type: 'null' title: Year - name: subject in: query required: false schema: anyOf: - type: string - type: 'null' title: Subject - name: location in: query required: false schema: anyOf: - type: string - type: 'null' title: Location - name: min_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Min Amt - name: max_amt in: query required: false schema: anyOf: - type: string - type: 'null' title: Max Amt responses: '200': description: Successful Response content: application/json: schema: {} '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' tags: - Grants description: 'One call for the whole shape of a filter: total dollars, grant count, distinct funders and recipients, plus a year-by-year breakdown. Cheaper than paging the rows to count them.' components: responses: Unauthorized: description: No API key, or a key we do not recognize. content: application/json: schema: $ref: '#/components/schemas/ApiError' example: code: 401 message: missing or invalid API key PaymentRequired: description: The monthly allowance is spent, the account is inactive, or the endpoint needs a paid plan. The message says which. content: application/json: schema: $ref: '#/components/schemas/ApiError' example: code: 402 message: monthly API call allowance spent schemas: HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type input: title: Input ctx: type: object title: Context type: object required: - loc - msg - type title: ValidationError ApiError: type: object description: Every failure answers with this envelope; `message` is safe to show a user. properties: code: type: integer message: type: string required: - code - message securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key description: Free key includes 50 calls a month; higher volume on a paid plan. Get one at https://data.useplinth.com/pricing. externalDocs: description: Developer documentation url: https://data.useplinth.com/developers