Charity Verify API
One API call to check tax-deductible eligibility, revocation status, group exemptions, and OFAC sanctions screening for any U.S. nonprofit.
Overview
The Charity Verify API cross-references multiple IRS data sources and OFAC sanctions lists to give you a single, definitive answer on whether a nonprofit can receive tax-deductible donations.
Data sources checked on every request:
- IRS Exempt Organizations Business Master File (EO BMF)
- IRS Publication 78 (eligible donees)
- IRS Auto-Revocation List (with reinstatement detection)
- Group Exemption resolution (subordinate → parent lookup)
- OFAC SDN & Consolidated sanctions lists (fuzzy matching)
- Form 990 leadership screening against OFAC
Authentication
All API requests require an API key passed in the x-api-key header.
# Include your key in every request curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/verify?ein=53-0196605"
To get an API key, contact support@givalgo.ai. Keys are scoped to a usage plan (Free, Basic, or Pro) which determines your rate limits.
Keep your API key secure. Do not expose it in client-side code or public repositories. If compromised, contact support for a key rotation.
Quickstart
Get up and running in 60 seconds.
cURL
# Verify American Red Cross curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/verify?ein=53-0196605"
Python
import requests response = requests.get( "https://api.givalgo.ai/v1/verify", params={"ein": "53-0196605"}, headers={"x-api-key": "YOUR_API_KEY"} ) data = response.json() if data["deductible"]: print(f"{data['organization']['name']} is eligible!") else: print(f"Status: {data['status']} - {data['message']}")
JavaScript
const response = await fetch( "https://api.givalgo.ai/v1/verify?ein=53-0196605", { headers: { "x-api-key": "YOUR_API_KEY" } } ); const data = await response.json(); console.log(data.status, data.organization?.name);
Verify Endpoint
Returns a complete verification of the nonprofit identified by the given EIN, including tax-deductible eligibility, revocation history, group exemption status, OFAC sanctions screening, and California state compliance (when applicable).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ein | string | Yes | Employer Identification Number. Accepts 13-1837418, 131837418, or 13 1837418. |
donor_state | string | No | Two-letter state code of the donor (e.g., CA). When set to CA, California AG + FTB compliance checks run even if the nonprofit is not CA-based. See California Compliance. |
ca_entity_id | string | No | California SOS/FTB entity number for direct lookup in the CA AG Registry and FTB Revocation list. Provides the highest coverage for California compliance checks. |
Response Fields
| Field | Type | Description |
|---|---|---|
status | string | Overall verification result (see Statuses) |
deductible | boolean | Whether donations are tax-deductible. null if not found. |
message | string | Human-readable explanation |
organization | object | IRS EO BMF data (name, city, state, subsection, foundation type, assets, income, NTEE code) |
pub78 | object | Publication 78 listing and deductibility type (PC, PF, POF, SO, etc.) |
revocation | object | Auto-revocation history and reinstatement status |
group_exemption | object | Present when ELIGIBLE via group exemption. Shows parent org details. Only applies to 501(c)(3) subordinates. |
sanctions_screening | object | OFAC screening results (see Sanctions Screening below for match object details) |
state_compliance | object | absent | Present only when California compliance checks are triggered. Contains california sub-object with AG registry and FTB status. See California Compliance. |
data_freshness | object | ISO dates showing when each source agency last published their data file (eo_bmf, pub78, revocation, ofac_sdn, ofac_cons) |
checked_at | string | ISO 8601 timestamp of this verification |
sanctions_screening object
| Field | Type | Description |
|---|---|---|
status | string | CLEAR, POTENTIAL_MATCH, STRONG_MATCH, or NOT_SCREENED |
organization_screening | object | Org name screened against OFAC entity entries |
.checked_name | string | Organization name that was screened |
.matches_found | integer | Number of OFAC matches |
.matches[] | array | Array of match objects (see below) |
leadership_screening | object | Form 990 officers/directors screened against OFAC individuals |
.people_data_tax_year | integer | null | Tax year of the Form 990 people data used for screening (e.g., 2023). Null if no people data found. |
.people_checked | integer | Number of people screened from Form 990 |
.people_screened[] | array | List of officers/directors/key employees screened, each with name and title |
.name | string | Person's name as reported on Form 990 |
.title | string | Person's title/role (e.g., "EXECUTIVE DIRECTOR", "BOARD PRESIDENT") |
.matches_found | integer | Number of OFAC matches |
.matches[] | array | Array of match objects (see below) |
checked_against | array | ["OFAC SDN", "OFAC Consolidated"] |
screened_at | string | ISO 8601 timestamp of screening |
Match object (within matches[])
| Field | Type | Description |
|---|---|---|
source | string | "OFAC SDN" or "OFAC Consolidated" |
matched_name | string | Name from OFAC list that matched |
matched_via | string | "primary_name" or "alias (a.k.a. ...)" |
primary_name | string | Primary OFAC name (only present for alias matches) |
similarity_score | number | Fuzzy match score (0.7–1.0). ≥0.9 = STRONG, ≥0.7 = POTENTIAL |
match_strength | string | "STRONG" or "POTENTIAL" |
sdn_type | string | OFAC entity type ("individual", "N" for entity/org) |
program | string | OFAC sanctions program (e.g., "SDGT", "IRAN") |
entry_id | integer | OFAC entry number |
remarks | string | OFAC remarks — often contains date of birth, nationality, passport numbers, and other identifying information. Key for false positive disambiguation. |
addresses | array | Known addresses for this OFAC entry. Each has address, city_state_zip, and country fields. |
Verification Statuses
| Status | Deductible | Meaning |
|---|---|---|
ELIGIBLE | true | Listed in IRS Pub 78 (directly or via group exemption for 501(c)(3) subordinates). Eligible for tax-deductible donations. |
NOT_DEDUCTIBLE | false | In IRS records but not tax-deductible (e.g., 501(c)(4), 501(c)(6)). |
REVOKED | false | Tax-exempt status auto-revoked by the IRS for non-filing. May appear even if the organization has dropped off the Business Master File. |
CAUTION | null | Federally eligible but flagged for review. Possible reasons: (1) In IRS master file as 501(c)(3) but not yet in Pub 78, or (2) California state compliance issue — the organization is delinquent, revoked, or suspended with the CA Attorney General or Franchise Tax Board. Check the message and state_compliance fields for specifics. |
NOT_FOUND | null | Not in IRS records and not on the revocation list. Churches and self-declared orgs may not appear. |
Sanctions Screening
Every verification includes an automated OFAC screening of the organization name and its leadership (officers, directors, key employees from Form 990). Matches are checked against both SDN and Consolidated lists, including primary names and aliases.
Overall status
| Status | Meaning |
|---|---|
CLEAR | No OFAC matches found for the organization or its leadership. |
POTENTIAL_MATCH | Fuzzy match with 70–89% similarity. Manual review recommended. |
STRONG_MATCH | Fuzzy match with 90%+ similarity. Very likely the same entity. |
NOT_SCREENED | OFAC screening was not performed (e.g., organization not found in IRS database). See the reason field for details. |
Disambiguation fields
When matches are found, each match object includes remarks and addresses to help you distinguish true positives from false positives:
remarks— OFAC remarks field containing date of birth, nationality, passport numbers, and other identifying informationaddresses— known addresses for the matched OFAC entry (street, city/state/zip, country)
Example match object
{
"source": "OFAC SDN",
"matched_name": "SMITH, John A.",
"matched_via": "primary_name",
"similarity_score": 0.912,
"match_strength": "STRONG",
"sdn_type": "individual",
"program": "SDGT",
"entry_id": 12345,
"remarks": "DOB 15 Mar 1970; nationality Iran; Passport A1234567",
"addresses": [
{
"address": "123 Example St",
"city_state_zip": "Tehran",
"country": "Iran"
}
]
}In this example, a board member named "John Smith" matched an OFAC entry — but the remarks show an Iranian DOB/passport, and the addresses show Tehran. If your board member is based in Ohio with a different DOB, this is a false positive you can confidently dismiss.
California Compliance
California AB 488 requires fundraising platforms to verify that nonprofits are in good standing with three authorities before facilitating donations involving a California donor or a California-based nonprofit:
- IRS — federal tax-exempt status (always checked)
- CA Attorney General — Registry of Charitable Trusts registration status
- CA Franchise Tax Board — state tax-exempt status (revocation check)
The API automatically runs California checks when the nonprofit is based in CA (per IRS records) or when you provide donor_state=CA. You can also provide ca_entity_id to trigger checks directly.
When do CA checks run?
| Nonprofit State | donor_state | CA Checks? |
|---|---|---|
| CA | (blank) | Yes — nonprofit is CA-based |
| Non-CA | (blank) | No |
| Any | CA | Yes — donor is in CA |
| Any | Non-CA | Only if nonprofit is CA-based |
| Any | Any | Yes — if ca_entity_id is provided |
Lookup cascade
The API uses a three-tier lookup to maximize coverage across the CA AG Registry (556K records):
ca_entity_id— direct SOS/FTB# lookup (97% of AG records have this)- FEIN — federal EIN match (covers ~58% of AG records)
- Name + city — fuzzy match fallback using trigram similarity (≥0.65 threshold with city filter, ≥0.80 without)
The match_method field in the response tells you which tier was used: ca_entity_id, fein, or name_match.
state_compliance.california object
| Field | Type | Description |
|---|---|---|
trigger | string | Why CA checks ran: nonprofit_based_in_ca, donor_state_ca, or ca_entity_id_provided |
ag_registry | object | CA Attorney General Registry result |
.status | string | REGISTERED, EXEMPT, DELINQUENT, REVOKED, SUSPENDED, CLOSED, NOT_REGISTERED, NON_COMPLIANT, or NOT_FOUND |
.registry_status | string | Raw status from CA AG (e.g., "Current", "Delinquent", "Exempt - Religious") |
.reg_number | string | State charity registration number (e.g., CT0252232) |
.match_method | string | ca_entity_id, fein, or name_match |
.matched_name | string | Present for name_match — the CA AG name that matched |
.name_similarity | number | Present for name_match — similarity score (0.65–1.0) |
ftb | object | CA Franchise Tax Board revocation result |
.status | string | CLEAR or REVOKED |
.revocation_date | string | Date of FTB revocation (if revoked) |
state_status | string | Roll-up: COMPLIANT, NON_COMPLIANT, REVOKED, or UNKNOWN |
Impact on overall status
| AG Registry | FTB | state_status | Overall status |
|---|---|---|---|
| REGISTERED / EXEMPT | CLEAR | COMPLIANT | No change |
| DELINQUENT / REVOKED / SUSPENDED | CLEAR | NON_COMPLIANT | ELIGIBLE → CAUTION |
| Any | REVOKED | REVOKED | ELIGIBLE → CAUTION |
| NOT_FOUND | CLEAR | UNKNOWN | No change |
Note: UNKNOWN (organization not found in CA AG) does not penalize the overall status. This may indicate the organization is exempt from CA registration (churches, schools, hospitals, or organizations receiving under $25,000 annually).
Example response
{
"status": "CAUTION",
"message": "This organization is listed in IRS Publication 78 ... However, California state compliance checks indicate that the organization's California Attorney General registration status is 'Delinquent'. Under California AB 488, fundraising platforms must verify state-level good standing before facilitating donations.",
"state_compliance": {
"california": {
"trigger": "nonprofit_based_in_ca",
"ag_registry": {
"status": "DELINQUENT",
"registry_status": "Delinquent",
"reg_number": "CT0252232",
"last_renewal_date": "2018-05-01",
"date_status_set": "2020-02-21",
"match_method": "fein"
},
"ftb": {
"status": "CLEAR"
},
"state_status": "NON_COMPLIANT"
}
}
}Rate Limits
Rate limits are applied per API key based on your plan tier.
| Plan | Requests / day | Burst | Rate |
|---|---|---|---|
| Free | 5 | 2/sec | 1/sec |
| Basic | 1,000 | 10/sec | 5/sec |
| Pro | 10,000 | 50/sec | 25/sec |
When you exceed your rate limit, the API returns 429 Too Many Requests. The response includes a Retry-After header indicating when you can retry.
Playground
Test the API directly from your browser. Enter your API key and an EIN to see a live response.
Try it now
Bulk Verify API
Verify hundreds or thousands of EINs in a single async request. Same 5-step verification, delivered at scale.
Overview
The Bulk Verify API accepts up to 250 EINs (semicolon-separated) or 20,000 EINs (CSV upload), processes them asynchronously via background workers, and delivers results via polling endpoint, webhook callback, or CSV download.
Each EIN goes through the same verification as the single Verify endpoint — IRS data cross-referencing, group exemption resolution, and OFAC sanctions screening.
How it works
- Submit — POST your EINs to
/v1/bulk-verify. Get back ajob_idimmediately (202 Accepted). - Process — EINs are split into batches of 10 and verified in parallel by background workers.
- Retrieve — Poll
GET /v1/bulk-verify/{job_id}for progress and results, or receive a webhook callback on completion.
| Input Method | Max EINs | Format |
|---|---|---|
| JSON body (semicolon-separated) | 250 | application/json |
| CSV file upload | 20,000 | multipart/form-data |
Authentication
All API requests require an API key passed in the x-api-key header — the same key used for the single Verify endpoint.
# Include your key in every request curl -X POST "https://api.givalgo.ai/v1/bulk-verify" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"eins": "13-1837418;53-0196605"}'
To get an API key, contact support@givalgo.ai. Keys are scoped to a usage plan (Free, Basic, or Pro) which determines your rate limits and max EINs per job.
Job ownership: Jobs are scoped to your API key. You can only view the status and results of jobs you created.
Quickstart
Submit a bulk job and poll for results in under a minute.
cURL — Submit + Poll
# 1. Submit a bulk job curl -X POST "https://api.givalgo.ai/v1/bulk-verify" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "eins": "13-1837418;53-0196605;06-0646973", "format": "both" }' # Response: {"job_id": "bulk_abc123", "status": "PROCESSING", ...} # 2. Poll for results curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/bulk-verify/bulk_abc123"
Python
import requests, time # Submit bulk job resp = requests.post( "https://api.givalgo.ai/v1/bulk-verify", headers={"x-api-key": "YOUR_API_KEY"}, json={ "eins": "13-1837418;53-0196605;06-0646973", "format": "both" } ) job = resp.json() job_id = job["job_id"] # Poll until complete while True: status = requests.get( f"https://api.givalgo.ai/v1/bulk-verify/{job_id}", headers={"x-api-key": "YOUR_API_KEY"} ).json() if status["status"] == "COMPLETED": print(f"Done! {status['summary']}") break time.sleep(2)
JavaScript
// Submit bulk job const resp = await fetch("https://api.givalgo.ai/v1/bulk-verify", { method: "POST", headers: { "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ eins: "13-1837418;53-0196605;06-0646973", format: "both" }) }); const { job_id } = await resp.json(); // Poll until complete const poll = async () => { const res = await fetch( `https://api.givalgo.ai/v1/bulk-verify/${job_id}`, { headers: { "x-api-key": "YOUR_API_KEY" } } ); const data = await res.json(); if (data.status === "COMPLETED") return data; await new Promise(r => setTimeout(r, 2000)); return poll(); }; const results = await poll();
Submit Bulk Job
Submit EINs for bulk verification. Returns 202 Accepted with a job_id for tracking.
JSON body (semicolon-separated EINs)
curl -X POST "https://api.givalgo.ai/v1/bulk-verify" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "eins": "13-1837418;53-0196605;06-0646973", "webhook_url": "https://your-server.com/hook", "format": "both" }'
CSV file upload
curl -X POST "https://api.givalgo.ai/v1/bulk-verify" \ -H "x-api-key: YOUR_API_KEY" \ -F "file=@organizations.csv" \ -F "webhook_url=https://your-server.com/hook"
CSV must have an ein column header (case-insensitive). Falls back to the first column if no header match.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
eins | string | Yes* | Semicolon-separated EINs. *Not needed for CSV upload. |
webhook_url | string | No | URL to POST results to on job completion. |
format | string | No | Result format: "json", "csv", or "both" (default). |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
skip_invalid | boolean | false | If true, skip invalid EINs and process only valid ones. If false, return a 400 error listing all invalid EINs. |
Response (202 Accepted)
{
"job_id": "bulk_a1b2c3d4e5f6",
"status": "PROCESSING",
"total_eins": 247,
"duplicates_removed": 3,
"estimated_seconds": 8,
"poll_url": "/v1/bulk-verify/bulk_a1b2c3d4e5f6",
"created_at": "2026-03-25T14:30:00Z"
}Validation error (400)
If any EINs fail validation (and skip_invalid is not set), you get a 400 with details:
{
"error": "VALIDATION_ERROR",
"message": "3 EINs failed validation",
"invalid_eins": [
{ "ein": "123", "error": "EIN must be exactly 9 digits" }
],
"valid_count": 247,
"hint": "Add ?skip_invalid=true to process only valid EINs."
}Poll Job Status
Check the progress and retrieve results of a bulk verification job. Jobs are scoped to your API key — you can only access jobs you created.
In progress
{
"job_id": "bulk_a1b2c3d4e5f6",
"status": "PROCESSING",
"progress": {
"total": 247,
"completed": 180,
"failed": 2,
"percent_complete": 73.7
}
}Completed
For jobs with 1,000 or fewer EINs, results are included inline. Larger jobs return a csv_download_url only. Each result in the array is a full single-verify response — identical to what you'd get from the /v1/verify endpoint, including organization details, Pub78, revocation history, and OFAC sanctions screening.
{
"job_id": "bulk_a1b2c3d4e5f6",
"status": "COMPLETED",
"summary": {
"eligible": 200,
"not_deductible": 30,
"revoked": 5,
"not_found": 8,
"ofac_flags": 3
},
"results": [
{
"ein": "13-1837418",
"ein_raw": "131837418",
"status": "ELIGIBLE",
"deductible": true,
"message": "Organization is eligible to receive tax-deductible donations.",
"organization": { /* full org details: name, city, state, NTEE, assets, ... */ },
"pub78": { /* listed, deductibility_code, description */ },
"revocation": { /* ever_revoked, currently_revoked, dates */ },
"sanctions_screening": { /* status, org & leadership screening, matches */ },
"checked_at": "2026-03-25T23:11:10Z",
"api_version": "v1"
},
// ... one entry per EIN, same structure as single /v1/verify response
],
"csv_download_url": "https://...presigned...",
"completed_at": "2026-03-25T14:30:07Z"
}CSV download
The csv_download_url (pre-signed S3 URL, valid 1 hour) contains a flattened version of the full results with 37 columns covering organization details, Pub78 status, revocation history, and OFAC screening. Column headers:
ein, status, deductible, message, org_name, org_city, org_state, subsection_code, subsection_label, deductibility_code, deductibility_label, foundation_code, foundation_label, status_code, status_label, affiliation_code, affiliation_label, group_exemption_number, ruling_date, ntee_code, asset_amount, income_amount, revenue_amount, pub78_listed, pub78_deductibility_code, pub78_deductibility_description, pub78_via_group_exemption, ever_revoked, currently_revoked, revocation_date, revocation_posting_date, reinstatement_date, sanctions_status, ofac_org_matches_found, ofac_leadership_matches_found, screened_at, error_message, checked_at
Job statuses
| Status | Meaning |
|---|---|
PROCESSING | Job is actively being processed by background workers. |
COMPLETED | All EINs have been verified. Results are available. |
Webhooks
If you provide a webhook_url when submitting a bulk job, we'll POST a notification when the job completes. This is the recommended approach for large jobs instead of polling.
Webhook payload
# POST to your webhook_url # Headers: # Content-Type: application/json # User-Agent: Givalgo-Webhook/1.0 # X-Givalgo-Event: bulk_verify.completed # X-Givalgo-Job-Id: bulk_a1b2c3d4e5f6 { "event": "bulk_verify.completed", "job_id": "bulk_a1b2c3d4e5f6", "status": "COMPLETED", "total_eins": 247, "completed": 245, "failed": 2, "summary": { "eligible": 200, "not_deductible": 30, "ofac_flags": 3 }, "csv_download_url": "https://...presigned-url...24hr-expiry...", "poll_url": "/v1/bulk-verify/bulk_a1b2c3d4e5f6" }
Retry policy
Webhook delivery is attempted up to 3 times with exponential backoff (1s, 5s delays). If your endpoint returns a 2xx status, delivery is marked as successful. The csv_download_url is a pre-signed S3 URL valid for 24 hours.
Throughput
| EINs | Estimated Time |
|---|---|
| 10 | ~5 seconds |
| 50 | ~15 seconds |
| 250 | ~30 seconds |
| 1,000 | ~2 minutes |
| 20,000 | ~40 minutes |
Job Statuses
A bulk job progresses through these statuses:
| Status | Meaning |
|---|---|
PROCESSING | Job is queued and actively being processed by background workers. Poll for progress updates. |
COMPLETED | All EINs have been verified. Results are available inline (for jobs ≤ 1,000 EINs) and via CSV download URL. |
Verification Statuses
Each EIN in a bulk job receives the same verification statuses as the single Verify endpoint:
| Status | Deductible | Meaning |
|---|---|---|
ELIGIBLE | true | Listed in IRS Pub 78 (directly or via group exemption). Eligible for tax-deductible donations. |
NOT_DEDUCTIBLE | false | In IRS records but not tax-deductible (e.g., 501(c)(4), 501(c)(6)). |
REVOKED | false | Tax-exempt status auto-revoked by the IRS for non-filing. May appear even if the organization has dropped off the Business Master File. |
CAUTION | null | In IRS master file as 501(c)(3) but NOT in Pub 78. May be a data timing lag — verify via the IRS Tax Exempt Organization Search. |
NOT_FOUND | null | Not in IRS records and not on the revocation list. Churches and self-declared orgs may not appear. |
Limits & Throughput
Bulk job limits are applied per API key based on your plan tier.
| Limit | Value |
|---|---|
| Max EINs (JSON body) | 250 |
| Max EINs (CSV upload) | 20,000 |
| Max concurrent jobs | 5 per API key |
| Result retention | 30 days |
| CSV download URL expiry | 24 hours |
Estimated processing times
| EINs | Estimated Time |
|---|---|
| 10 | ~5 seconds |
| 50 | ~15 seconds |
| 250 | ~30 seconds |
| 1,000 | ~2 minutes |
| 20,000 | ~40 minutes |
Processing time depends on current load and Lambda warm-start state. For time-sensitive workloads, use a webhook for instant notification on completion.
Report API
Generate professional, branded PDF verification reports for any U.S. nonprofit — ready to share with donors, board members, or compliance teams.
Overview
The Report API takes an EIN and returns a multi-page PDF document containing the same verification data as the Verify endpoint — presented in a polished, print-ready format with Givalgo branding.
Each report includes a cover page, verification outcome with status badge, IRS data breakdown, OFAC sanctions screening results, financial snapshot, and a branded back page.
application/pdf
Authentication
The Report API uses the same API key authentication as the Verify and Bulk Verify endpoints. Include your key in the x-api-key header:
curl -H "x-api-key: YOUR_API_KEY" \ -H "Accept: application/pdf" \ "https://api.givalgo.ai/v1/report?ein=13-1837418" \ -o report.pdf
Quickstart
Generate your first PDF report in seconds:
# Download a verification report for Candid (EIN 13-1837418) curl -H "x-api-key: YOUR_API_KEY" \ -H "Accept: application/pdf" \ "https://api.givalgo.ai/v1/report?ein=13-1837418" \ -o candid-verification.pdf # Open the PDF open candid-verification.pdf
Tip: Include the Accept: application/pdf header to receive decoded binary PDF.
In Postman, use Send and Download (dropdown next to Send) to save the file.
Report Endpoint
Takes an EIN and returns a professionally formatted PDF verification report. The underlying data is identical to the /v1/verify endpoint — the Report API simply renders it into a branded, multi-page PDF document.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ein | string | Yes | Employer Identification Number. Accepts 13-1837418, 131837418, or 13 1837418. |
Headers
| Header | Required | Description |
|---|---|---|
x-api-key | Yes | Your API key |
Accept | Recommended | Set to application/pdf for decoded binary response |
Success Response
| Property | Value |
|---|---|
| Status Code | 200 OK |
| Content-Type | application/pdf |
| Content-Disposition | inline; filename="npo-verify-{ein}.pdf" |
Error Responses
Error responses are returned as JSON (not PDF):
| Status | Error Code | Description |
|---|---|---|
400 | MISSING_EIN | The ein query parameter was not provided |
400 | INVALID_EIN | EIN format is invalid (not 9 digits) |
403 | Forbidden | Missing or invalid API key |
500 | INTERNAL_ERROR | Server-side error during PDF generation |
Note: All valid verification statuses (ELIGIBLE, REVOKED, NOT_FOUND, CAUTION, NOT_DEDUCTIBLE) return a 200 with a PDF. Only auth or input errors return JSON.
Report Sections
Each generated PDF contains the following pages:
| Page | Section | Content |
|---|---|---|
| 1 | Cover Page | Givalgo branding, organization name, EIN, report generation date |
| 2 | Outcome & Details | Large status badge (color-coded), deductibility verdict, organization details (city, state, subsection, NTEE code, ruling date) |
| 3 | IRS Status Breakdown | EO BMF status & deductibility, Pub 78 listing, group exemption details, revocation history with dates |
| 4 | OFAC Screening | Organization & leadership sanctions screening status, match details (if any), data source year |
| 5 | Financial Snapshot | Total assets, annual income, annual revenue (from IRS BMF data) |
| 6 | Back Page | Disclaimer, API version, generation timestamp, contact info |
Verification Statuses
The report displays the same verification statuses as the Verify endpoint, rendered as color-coded badges:
| Status | Badge Color | Deductible | Meaning |
|---|---|---|---|
ELIGIBLE | ● Green | Yes | Listed in IRS Pub 78. Eligible for tax-deductible donations. |
NOT_DEDUCTIBLE | ● Orange | No | In IRS records but not tax-deductible. |
REVOKED | ● Red | No | Tax-exempt status auto-revoked by the IRS. |
CAUTION | ● Yellow | Unconfirmed | In IRS master file as 501(c)(3) but not in Pub 78. |
NOT_FOUND | ● Gray | Unknown | Not in IRS records. Churches and self-declared orgs may not appear. |
Important Notes
Response Time
PDF generation typically takes 2–4 seconds (cold start may add 3–5 seconds on first request). The API Gateway timeout is 29 seconds.
Data Source
Reports contain the same data as the /v1/verify endpoint. The PDF is generated on-the-fly from live verification data — it is not cached. Each request produces a fresh report with the current timestamp.
File Size
Reports are typically 115–130 KB depending on the amount of data (e.g., OFAC matches increase size slightly).
Disclaimer
Each report includes a footer disclaimer: "This report is generated from publicly available IRS data and OFAC sanctions lists. It does not constitute legal or tax advice."
Form 990 Data API
Structured access to every meaningful number, ratio, and peer benchmark from U.S. nonprofit Form 990 filings — for 3.3M+ filings covering 1.9M+ unique organizations.
Overview
The Form 990 Data API turns raw IRS e-file XML into a clean JSON response covering financials, compensation, programs, governance, fundraising, liquidity, expense composition, related organizations, foreign activity, and more. Every core ratio is benchmarked against peer cohorts (NTEE major group × revenue band × state), so you see not just the number but where it sits in its sector.
Two tiers share the same endpoint family:
/v1/dataBase — ~150 fields, all core sections, all peer benchmarks/v1/data-proPro — base + three deep-detail attachments (~410 fields total)
Tiers: Data vs Data Pro
Tier is determined entirely by the endpoint path — there is no public include= parameter. Both tiers accept the same query parameters (ein, tax_year) and require the same x-api-key header.
| Section | /v1/data Base | /v1/data-pro Pro |
|---|---|---|
organization — identity, NTEE, mission | ✓ | ✓ |
financials — revenue, expenses, balance sheet | ✓ | ✓ |
trends — 6-year annual series + CAGR + trend labels | ✓ | ✓ |
compensation — officers, by_role, peer benchmarks | ✓ | ✓ |
funding_sources — grantmakers received from | ✓ | ✓ |
programs — program descriptions + expenses | ✓ | ✓ |
governance — board + policies | ✓ | ✓ |
fundraising — events, professional fundraisers | ✓ | ✓ |
financial_profile — liquidity, HHI, expense composition New | ✓ | ✓ |
related_organizations | ✓ | ✓ |
foreign_activities, lobbying_and_political, donor_advised_funds | ✓ | ✓ |
data_freshness | ✓ | ✓ |
financials_detail — full Schedule A-D line items Pro | – | ✓ |
governance_detail — full board roster, policies, minutes | – | ✓ |
registration — Schedule R + B + state-level filings | – | ✓ |
New indicates fields added in the April 2026 release.
Authentication
All requests require an API key passed in the x-api-key header. Keys are scoped to a usage plan (Free, Base, Pro) which determines rate limits and tier access.
# Base tier curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/data?ein=53-0196605" # Pro tier curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/data-pro?ein=53-0196605"
To upgrade to Pro or request a trial key, contact support@givalgo.ai.
Quickstart
cURL — most recent filing
curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/data?ein=53-0196605"
cURL — specific tax year
curl -H "x-api-key: YOUR_API_KEY" \ "https://api.givalgo.ai/v1/data?ein=53-0196605&tax_year=2022"
Python
import requests r = requests.get( "https://api.givalgo.ai/v1/data-pro", params={"ein": "53-0196605"}, headers={"x-api-key": "YOUR_API_KEY"}, ) data = r.json() name = data["organization"]["name"] prog_pct = data["financial_profile"]["expense_composition"]["program_expense_ratio"] peer_median = data["financial_profile"]["expense_composition"] \ ["peer_benchmarks_by_metric"]["program_expense_ratio"] \ ["by_ntee_and_revenue_band_and_state"]["median"] print(f"{name}: program = {prog_pct:.0%}, peer median = {peer_median:.0%}")
JavaScript
const r = await fetch( "https://api.givalgo.ai/v1/data?ein=53-0196605", { headers: { "x-api-key": "YOUR_API_KEY" } } ); const data = await r.json(); console.log(data.organization.name, data.trends.computed.revenue_trend);
Endpoints
Returns base sections (~150 fields): organization, financials, trends, compensation, funding_sources, programs, governance, fundraising, financial_profile, related_organizations, foreign_activities, lobbying_and_political, contributor_summary, donor_advised_funds, data_freshness.
Returns the base shape plus three detail attachments (~410 fields total): financials_detail, governance_detail, registration.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ein | string | Yes | Employer Identification Number. Accepts 53-0196605, 530196605, or 53 0196605. |
tax_year | integer | No | 4-digit fiscal year (e.g. 2022). Omit to get the most recent filing. If the requested year has no filing, the response is a 404 with a years_available array. |
Response Top-Level
| Field | Type | Description |
|---|---|---|
ein | string | Hyphenated EIN (e.g. "53-0196605"). |
tax_year | integer | Fiscal year of the filing returned. |
return_type | string | "990", "990EZ", or "990PF". |
filing_date | string (ISO date) | Date IRS received the filing. |
organization | object | Identity, address, NTEE code, mission, formation year, total employees/volunteers. |
financials | object | Summary, revenue breakdown, expenses, balance sheet, and (Pro only) detail sub-object. |
trends | object | Up to 6 years of annual data + computed CAGRs + trend labels. |
compensation | object | People array, by-role highlights, per-employee average, peer benchmark cubes. |
funding_sources | object | Grants received: grantmakers[], annual totals. |
programs | object | Program service accomplishments + grants made (recipients[]). |
governance | object | Board structure, policies, meeting minutes flags. |
fundraising | object | Events, professional fundraisers, state filings. |
financial_profile | object | Liquidity, revenue concentration (HHI), operating sustainability, expense composition New. All with peer benchmarks. |
related_organizations | object | Schedule R-style related entities. |
foreign_activities | object | Schedule F summary. |
lobbying_and_political | object | Schedule C summary. |
contributor_summary | object | Schedule B contributor aggregates. |
donor_advised_funds | object | DAF flags + balances (if Schedule D.I present). |
registration Pro | object | Registration and state-level filings detail. |
data_freshness | object | Filing source, most_recent_tax_year, last_filing_date, years_available[]. |
organization
| Field | Type | Description |
|---|---|---|
name | string | Legal name on the filing. |
also_known_as | string | null | DBA, if present. |
address, city, state, zip | string | Mailing address. |
phone, website | string | null | Contact info. |
formation_year | integer | Year of formation. |
mission | string | Mission statement text. |
principal_officer | string | null | Name of principal officer from Form 990 header. |
ntee_code | string | Full NTEE code (e.g. "P210"). |
ntee_description | string | Human-readable NTEE major group (e.g. "Human Services"). |
ruling_year | integer | null | Year IRS granted tax-exempt status. |
total_employees, total_volunteers | integer | As reported on the filing. |
financials
| Field | Type | Description |
|---|---|---|
summary | object | total_revenue, total_expenses, revenue_less_expenses, total_assets_eoy, total_liabilities_eoy, net_assets_eoy. |
revenue | object | contributions_and_grants, program_service_revenue, investment_income, other_revenue, total. |
expenses | object | program_services, management_and_general, fundraising, total, and allocation (program_pct, fundraising_pct). |
balance_sheet | object | Cash, investments, PP&E, assets, liabilities, net assets (with unrestricted split). |
detail Pro | object | null | Full Part VIII / Part IX / Schedule D line-by-line breakdown. null on base tier. |
trends
| Field | Type | Description |
|---|---|---|
years_available | integer[] | All tax years on file for this EIN. |
annual[] | object[] | Per-year rollup: total_revenue, total_expenses, total_assets_eoy, net_assets_eoy, contributions, program_service_revenue, investment_income, program_expense_ratio, fundraising_expense_ratio, months_of_cash, total_employees, top_officer_comp. |
computed.years_of_data | integer | Count of annual entries returned. |
computed.revenue_cagr_pct | number | Compound annual growth rate of revenue. |
computed.expense_cagr_pct | number | CAGR of expenses. |
computed.asset_cagr_pct | number | CAGR of net assets. |
computed.revenue_trend | string | Label: GROWING (>3% CAGR), STABLE, or DECLINING (<−3%). |
computed.expense_trend New | string | Matching label for expense CAGR. |
computed.asset_trend New | string | Matching label for asset CAGR. |
compensation
Top-level scalars are drawn from Form 990 Part VII (officers, key employees, highest-paid) and Part IX (salaries & benefits aggregate).
Top-level fields
| Field | Type | Description |
|---|---|---|
tax_year | integer | Fiscal year this compensation data belongs to. |
people_count | integer | Number of people in the people[] array. |
people[] | object[] | Array of Part VII persons with name, title, hours_per_week, is_officer, is_key_employee, is_director, is_highest_paid, reportable_comp_org, reportable_comp_related, other_compensation, total_compensation. |
highest_paid_person | string | Name of the highest-paid person in the list. |
highest_compensation | integer | Dollar amount. |
comp_to_expense_pct | number | Sum of Part VII compensation ÷ total expenses, as a percent. |
top_officer_comp_to_revenue_pct New | number | Top officer total comp ÷ total revenue, as a percent. Scale-normalized so small and large orgs can be compared fairly. |
avg_compensation_per_employee New | integer | Whole-org payroll ÷ total employees, in dollars. Sourced from Form 990 Part IX Lines 5-10 (salaries + benefits + pension + payroll tax). Populated for ~29% of filings where both fields are non-zero. |
by_role New
Highest-paid person whose title matches common patterns for each role. null per role if no match.
| Field | Type | Description |
|---|---|---|
by_role.ceo | object | null | {title, total_compensation}. Matches titles like Executive Director, Chief Executive, President, CEO. |
by_role.cfo | object | null | Matches titles like Chief Financial Officer, CFO, Treasurer, Director of Finance, VP Finance. |
by_role.development_director | object | null | Matches Chief Development Officer, Development Director, VP Development, Chief Advancement Officer. |
peer_benchmarks_by_metric New
One cube per metric — see How Cubes Work. Metrics with no peer data (e.g. small revenue bands) are omitted.
top_officer_comp— absolute top-officer dollar amountstop_officer_comp_to_revenue_pct— scale-normalizedceo_comp,cfo_comp,dev_director_comp— role-specific benchmarksavg_compensation_per_employee— whole-org payroll per FTE
The legacy key peer_benchmarks (top-level, not nested) remains for backwards compatibility and mirrors peer_benchmarks_by_metric.top_officer_comp.
funding_sources
Aggregated from Schedule I of grantmakers that reported this EIN as a grant recipient.
| Field | Type | Description |
|---|---|---|
grantmakers[] | object[] | Up to 50 most recent grantmakers: grantmaker_ein, grantmaker_name, grants_count, total_awarded, most_recent_year, most_recent_amount, purpose_summary. |
annual[] | object[] | Per-year: tax_year, total_received, unique_grantmakers. |
programs & grants
| Field | Type | Description |
|---|---|---|
programs[] | object[] | Program service accomplishments: name, description, expenses, revenue, grants_made. |
grants_made.recipients[] | object[] | Schedule I recipients: recipient_ein, recipient_name, amount, purpose, tax_year. |
grants_made.summary | object | Total amount, unique recipient count, top destination type. |
governance
| Field | Type | Description |
|---|---|---|
voting_board_members | integer | Total voting members. |
independent_board_pct | number | Percent independent. |
has_conflict_of_interest_policy | boolean | Part VI Line 12. |
has_whistleblower_policy, has_document_retention_policy | boolean | Part VI Lines 13-14. |
detail Pro | object | null | Full board roster + minutes-kept flags + compensation review process. null on base tier. |
fundraising
| Field | Type | Description |
|---|---|---|
professional_fundraisers[] | object[] | Schedule G Part I: name, activity, gross_receipts, amount_to_org. |
events[] | object[] | Schedule G Part II: event_name, gross_revenue, contributions, gross_income, direct_expenses, net_income. |
state_filings | object | States where fundraising is registered (from Schedule G). |
financial_profile
Our headline analytics section — every ratio here comes with a peer benchmark cube.
liquidity
| Field | Type | Description |
|---|---|---|
months_of_cash | number | Cash & savings ÷ monthly expenses. |
months_of_liquid_assets | number | Cash + savings + publicly traded investments, over monthly expenses. |
operating_reserve_months New | number | Unrestricted net assets ÷ monthly expenses. The standard donor-facing operating-reserve figure. |
peer_benchmarks | object | Legacy: 7-cut cube for months_of_cash. |
peer_benchmarks_by_metric New | object | Cubes for months_of_cash and operating_reserve_months. |
revenue_concentration
| Field | Type | Description |
|---|---|---|
herfindahl_index | number | HHI computed across 5 revenue buckets (contributions, program service, investment, fundraising events, other). Lower = more diversified. |
diversification_level | string | DIVERSIFIED (HHI < 0.30), MODERATE (0.30–0.55), or CONCENTRATED (≥ 0.55). Thresholds rebased April 2026 to match the real HHI floor of 0.20 (5 equal buckets). |
diversification_description New | string | Plain-English explanation of the bucket. |
index_range New | object | {min: 0.20, max: 1.00, buckets: 5, note: ...} — so consumers know how to interpret the scalar. |
operating_sustainability
| Field | Type | Description |
|---|---|---|
operating_margin_pct | number | (Revenue − expenses) ÷ |revenue|, percent. |
operating_reserve_months | number | Same as liquidity. |
peer_benchmarks_by_metric New | object | Cubes for both metrics. |
expense_composition New
Two views of where the dollars go — the functional split Charity Navigator uses, plus the FASB-required natural-category split from Form 990 Part IX.
Functional view (program / admin / fundraising)
| Field | Type | Description |
|---|---|---|
program_expense_ratio | number | Program services ÷ total expenses × 100. The traditional "how much goes to mission" ratio. |
admin_expense_ratio | number | Management & general ÷ total expenses × 100. |
fundraising_expense_ratio | number | Fundraising ÷ total expenses × 100. |
cost_to_raise_a_dollar | number | Fundraising expense ÷ contributions. Lower is more efficient. |
comp_to_expense_pct | number | Top-N compensation as percent of total expenses. |
Natural view (FTA — Part IX line items) New
| Field | Type | Description |
|---|---|---|
salaries_benefits_ratio | number | Part IX lines 5–10 ÷ total expenses × 100. Labor intensity — service-delivery orgs run 60–80%; grant-makers much lower. |
professional_fees_ratio | number | Part IX lines 11a–11g ÷ total expenses × 100. High values can flag heavy consultant / outside-fundraiser reliance. |
occupancy_ratio | number | Part IX line 16 ÷ total expenses × 100. Real-estate-heavy orgs (museums, hospitals) run higher. |
travel_ratio | number | Part IX line 17 ÷ total expenses × 100. |
grants_paid_ratio | number | Part IX lines 1–3 ÷ total expenses × 100. Grant-making foundations run very high; direct-service orgs near zero. |
salaries_benefits · professional_fees · occupancy · travel · grants_paid | integer | Raw Part IX dollar amounts — for callers that want their own cut (e.g. $/employee, $/beneficiary). |
peer_benchmarks_by_metric | object | Percentile cubes for the functional ratios + the two most universally benchmarkable FTA ratios (salaries_benefits_ratio, professional_fees_ratio). Occupancy / travel / grants_paid vary too much by org type to percentile meaningfully. |
Note: absolute third-party thresholds (Charity Navigator's 70% program benchmark, BBB Wise Giving's 65%, etc.) are deliberately NOT returned. Peer percentiles already place the org in its cohort, and absolute thresholds often penalize nonprofits for legitimate sector differences.
related_organizations / foreign_activities / lobbying / DAFs
| Section | Source | Description |
|---|---|---|
related_organizations | Schedule R | Disregarded entities, related tax-exempt orgs, related taxable partnerships/corps. Counts + optionally names (Pro). |
foreign_activities | Schedule F | Regions, activity types, revenue & expenditures abroad, foreign grants. |
lobbying_and_political | Schedule C | Lobbying expenditures (direct & grassroots), 501(h) election, political campaign expenditures. |
contributor_summary | Schedule B | Aggregate contributor counts + total contributions. Individual contributor names are never returned (IRS redaction). |
donor_advised_funds | Schedule D.I | Funds held, aggregate balance, contributions during year. |
data_freshness
| Field | Type | Description |
|---|---|---|
filing_source | string | Always "IRS TEOS e-file". |
most_recent_tax_year | integer | Latest filing year ingested for this EIN. |
filing_date | string | Filing date of the response year. |
last_filing_date | string | Most recent filing date for this EIN overall. |
years_available | integer[] | All tax years on file. |
includes_applied | string[] | Diagnostic — which internal bundles applied to this response (empty on base). |
Peer Benchmarks: How Cubes Work
Every ratio in compensation.peer_benchmarks_by_metric and financial_profile.*.peer_benchmarks_by_metric returns a cube: the same metric sliced across seven peer-group dimensions, each with the same six percentile stats.
Shape of a single cube
{
"by_ntee": { ...PeerStats },
"by_revenue_band": { ...PeerStats },
"by_state": { ...PeerStats },
"by_ntee_and_revenue_band": { ...PeerStats },
"by_ntee_and_state": { ...PeerStats },
"by_revenue_band_and_state": { ...PeerStats },
"by_ntee_and_revenue_band_and_state": { ...PeerStats }
}PeerStats
| Field | Type | Description |
|---|---|---|
peer_group | string | Human label, e.g. "P – Human Services ∩ $100M+ ∩ DC". |
peer_count | integer | Number of orgs in the cohort for that tax year. |
p10, p25, median, p75, p90, mean | number | Distribution statistics for the metric in that cohort. |
note | string (optional) | Appears when peer_count < 10: "Small peer group — interpret with caution". |
Peer Benchmarks: 7 Dimensional Cuts
Each cube is the same metric sliced seven ways. The intersection cuts (triple) are the narrowest and usually most meaningful, but may have small cohorts.
NTEE major group
A–Z first letter of the IRS National Taxonomy of Exempt Entities code. Examples: A Arts & Culture, B Education, E Health, P Human Services.
Revenue band
Eight bands based on total revenue: 1 <$100K, 2 <$500K, 3 <$1M, 4 <$5M, 5 <$10M, 6 <$50M, 7 <$100M, 8 $100M+.
State
Two-letter state code from the organization's mailing address.
Intersections
4 compound cuts: ntee ∩ revenue_band, ntee ∩ state, revenue_band ∩ state, and the triple ntee ∩ revenue_band ∩ state.
Peer Benchmarks: Metrics Covered
17 metrics currently ship with peer-benchmark cubes. New metrics are added as underlying data coverage grows.
| Metric | Surfaced at |
|---|---|
total_revenue | (internal reference) |
top_officer_comp | compensation.peer_benchmarks, compensation.peer_benchmarks_by_metric |
top_officer_comp_to_revenue_pct New | compensation.peer_benchmarks_by_metric |
ceo_comp New | compensation.peer_benchmarks_by_metric |
cfo_comp New | compensation.peer_benchmarks_by_metric |
dev_director_comp New | compensation.peer_benchmarks_by_metric |
avg_compensation_per_employee New | compensation.peer_benchmarks_by_metric |
program_expense_ratio | financial_profile.expense_composition.peer_benchmarks_by_metric |
admin_expense_ratio New | financial_profile.expense_composition.peer_benchmarks_by_metric |
fundraising_expense_ratio New | financial_profile.expense_composition.peer_benchmarks_by_metric |
cost_to_raise_a_dollar New | financial_profile.expense_composition.peer_benchmarks_by_metric |
comp_to_expense_pct | financial_profile.expense_composition.peer_benchmarks_by_metric |
salaries_benefits_ratio New | financial_profile.expense_composition.peer_benchmarks_by_metric |
professional_fees_ratio New | financial_profile.expense_composition.peer_benchmarks_by_metric |
months_of_cash | financial_profile.liquidity.peer_benchmarks, financial_profile.liquidity.peer_benchmarks_by_metric |
operating_reserve_months New | financial_profile.liquidity + operating_sustainability |
operating_margin_pct | financial_profile.operating_sustainability.peer_benchmarks_by_metric |
Pro-Only Attachments Pro
Calling /v1/data-pro attaches three extra sections on top of the base shape.
financials_detail
Line-by-line Part VIII (revenue) and Part IX (expenses) breakdowns plus Schedule A (public charity status), Schedule B (contributors summary), Schedule D (supplemental financials) highlights, Schedule O (narratives).
governance_detail
Full voting-board roster with titles, committee memberships, compensation-review process, meeting-minutes flags, and policies (conflict of interest, whistleblower, document retention, joint venture, independence).
registration
State-level registration filings (where ingested), Schedule R related-organization full roster with ownership percentages, foreign registration details.
Error Codes
| Status | Error | Meaning |
|---|---|---|
| 400 | MISSING_EIN | The ein query param is required. |
| 400 | INVALID_EIN | EIN is not 9 digits / not parseable. |
| 400 | INVALID_TAX_YEAR | tax_year must be a 4-digit integer. |
| 403 | IP_NOT_ALLOWED | The calling IP is not on the allowlist for this API key. |
| 403 | Forbidden | Missing or invalid x-api-key header. |
| 404 | NOT_FOUND | No filing for this EIN (or not for the requested year). Response includes years_available[]. |
| 500 | INTERNAL_ERROR | Unexpected server error. request_id included for support tickets. |
Rate Limits
| Plan | Requests / minute | Burst | Tier access |
|---|---|---|---|
| Free | 10 | 20 | Base only |
| Basic | 60 | 120 | Base only |
| Pro | 300 | 600 | Base + Pro |
| Enterprise | Custom | Custom | Base + Pro + bespoke attachments |
When you exceed a limit, API Gateway returns 429 Too Many Requests. Back off and retry after 30 seconds. Contact support@givalgo.ai to adjust plans.