Developer documentation · Professional plan
CauseComp API & connector docs
The same nonprofit compensation engine behind the CauseComp web tools, available as a token-authenticated REST API and as a one-click Claude connector. This page takes a non-technical reader from zero to a working call.
Overview
The CauseComp API answers the same questions as the website — executive pay from IRS Form 990 Schedule J, broad-based workforce pay from U.S. Bureau of Labor Statistics data, and the §4958 comparables set — and returns an answer identical to the site's for the same inputs, because both call one shared engine.
You need the Professional plan
API and connector access is a Professional feature. Every request checks your live plan, so access follows your subscription — a downgrade or cancellation disables your credentials automatically. See plans & pricing
Base URL
All REST endpoints live under one versioned base:
https://www.causecomp.org/api/v1
Authentication
Every request carries a bearer credential in the Authorization header.
Two credential types are accepted on the same header:
- An API key — a secret that starts with
cc_live_, which you mint on your account page. Use this with your own code or with Model Context Protocol clients other than Claude and ChatGPT. - The OAuth token from the Claude or ChatGPT connector — issued automatically when you connect CauseComp to Claude (on claude.ai or the desktop app) or to ChatGPT in developer mode. You never see or paste it; the connector's OAuth sign-in handles it. In either assistant, the connector requires a CauseComp Professional-plan account.
Either way, the header looks like this (the connector sets it for you):
Authorization: Bearer cc_live_your_key_here
Claude connector quickstart
The CauseComp connector works wherever you use Claude — connect it once and it follows your Claude account: claude.ai, the Claude desktop app, and Claude's integrations inside other tools where connectors are enabled. There are no API keys to copy for the one-click path — you sign in with your CauseComp account and approve access.
Open Connectors
In Claude, go to Settings → Connectors, click Add, then Add custom connector.
Fill in two fields
Name: CauseComp
Remote MCP server URL: https://mcp.causecomp.org/mcp
Leave everything under Advanced settings — OAuth Client ID and OAuth Client Secret — blank; sign-in comes next, no keys to paste. Then click Add.
Sign in & allow
Click Connect on the new CauseComp row, sign in with your CauseComp account, and Allow — you're benchmarking.
Once connected, ask in plain English — Claude calls CauseComp and returns the percentile figures, the data vintage, and the standard disclaimer. Full walkthrough and example prompts on the Claude connector page.
REST reference
Thirteen endpoints: five that answer a question
(POST, JSON body) and eight lookups (GET, query string). All require the
Authorization: Bearer header. Each successful call to one of the
five counts against your account's daily quota;
the lookups are not metered. revenue
accepts a dollar amount ("$5,000,000" or 5000000) or a band label.
Each endpoint below lists what it accepts, what it returns and what each returned field means. Some responses carry additional diagnostic fields; they may change without notice and should not be relied on. The example responses were produced by calling the API; long lists and long text are shortened, marked with …, and a filer's mission text is described rather than printed.
POST /executive/benchmark
Executive (officer / leadership) benchmark from 990 Schedule J.
Professional plan. Each successful call counts as one call against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| role | required | Executive role label (resolve fuzzy input via /meta/exec_roles). |
| ntee_sector | required | NTEE sector label (see /meta/sectors). |
| state | required | Two-letter state code, e.g. CA, or US for the national benchmark with no state adjustment (see /meta/states). An unrecognized value returns a correction listing the valid codes; it is never served as the national figure. |
| revenue | required | Annual budget size (amount or band label). A band label is accepted and is treated as that band's midpoint, so a figure near a band edge will differ from the band; prefer the exact figure when the caller knows it. A revenue of 0 is answered without a modeled figure (see modelled_figure). |
| org_type | optional | optional. IRS subsection, e.g. 501(c)(3). It is not a filter: the comparison group does not narrow to that type. For 501(c)(3), 501(c)(6), 501(c)(7), 501(c)(8) and 501(c)(9) the figure is adjusted by a factor measured for that subsection. Any other value is recorded but does not change the benchmark. The response says whether the adjustment was applied. |
| ntee_subsector | optional | Three-character NTEE subsector code (e.g. P20) for finer calibration. |
| msa | optional | Metro code (see /meta/metros). |
| age_to_date | optional | Optional. Project the figures to this exact date (YYYY-MM-DD) using CauseComp's measured nonprofit pay growth, or aging_rate if supplied; omit for as-filed figures. If the date is beyond the measured table's reach, the response says which date the figures were projected to instead (money_aging_clamped). |
| age_to_year | optional | Optional. Project the figures to 31 December of this calendar year - the same as age_to_date set to that day; omit for as-filed figures. Ignored when age_to_date is given. |
| aging_rate | optional | Optional, and only alongside age_to_year: a yearly growth rate in percent (e.g. 3.0) to use instead of the measured growth rate. The response names it as the source (money_aging_source = user-supplied). |
Example request
curl https://www.causecomp.org/api/v1/executive/benchmark \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "ntee_sector": "Human Services", "state": "CA", "revenue": "$5,000,000"}'
Example response
{
"benchmark": {
"aged_from_date": null,
"aged_from_year": null,
"aged_to_date": null,
"aged_to_year": null,
"base_median": 140832,
"base_n_disclosed": null,
"base_p10": 82130,
"base_p25": 105976,
"base_p75": 189227,
"base_p90": 263034,
"base_pct_nonzero": null,
"benefits_median": 6972,
"benefits_n_disclosed": null,
"benefits_p10": 4066,
"benefits_p25": 5246,
"benefits_p75": 9368,
"benefits_p90": 13021,
"benefits_pct_nonzero": null,
"bonus_label": "Of nonprofit executives paid about $155,000, across all roles and sectors, 28% received a bonus. Those who …",
"bonus_median": 2182,
"bonus_n_disclosed": null,
"bonus_p10": 1272,
"bonus_p25": 1642,
"bonus_p75": 2932,
"bonus_p90": 4075,
"bonus_pct_nonzero": null,
"bonus_prevalence_pct": 28,
"bonus_typical_pct": 4.8,
"components_aged": false,
"components_basis": "modelled_share",
"components_cohort_n": null,
"components_under_10_filings": [],
"confidence": "High",
"confidence_basis": "Confidence describes the depth of filing evidence for this benchmark. It is not a statistical confidence …",
"data_vintage": "990 data",
"filed_titles": {
"n_distinct_titles": 8684,
"n_filings": 113213,
"titles": [
{
"n_filings": 52581,
"title": "Executive Director"
},
{
"n_filings": 13132,
"title": "CEO"
},
// … 4 more
]
},
"filings_aged": false,
"geographic_basis": "state",
"geographic_fallback_reason": null,
"is_bls_primary": false,
"median": 155118,
"method": "base (role x revenue) + location + NTEE",
"modelled_figure": true,
"money_aging_clamped": null,
"money_aging_declined": null,
"money_aging_eci_vintage": null,
"money_aging_factor": null,
"money_aging_rate_pct": null,
"money_aging_refusal": null,
"money_aging_requested_year": null,
"money_aging_source": null,
"n_obs": 83173,
"no_modelled_figure_reason": null,
"org_type_modifier_applied": false,
"org_type_modifier_declined": null,
"org_type_modifier_factor": null,
"org_type_modifier_source": null,
"other_median": 215,
"other_n_disclosed": null,
"other_p10": 125,
"other_p25": 161,
"other_p75": 288,
"other_p90": 401,
"other_pct_nonzero": null,
"p10": 90462,
"p25": 116727,
"p50": 155118,
"p75": 208423,
"p90": 289717,
"retirement_deferred_median": 3297,
"retirement_deferred_n_disclosed": null,
"retirement_deferred_p10": 1923,
"retirement_deferred_p25": 2481,
"retirement_deferred_p75": 4431,
"retirement_deferred_p90": 6159,
"retirement_deferred_pct_nonzero": null,
"revenue_band": "$5M–$10M",
"role_filings_note": null,
"role_filings_thin": false,
"warning": ""
},
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"input": {
"msa": null,
"ntee_sector": "Human Services",
"ntee_subsector": null,
"org_type": null,
"revenue_raw": "$5,000,000",
"role": "Executive Director / CEO",
"state": "CA"
}
}
What comes back
| Field | What it means |
|---|---|
| benchmark | The figures, described in the next table. |
| input | Your inputs as interpreted: the canonical role, sector and state labels, and revenue_raw as you sent it. |
| disclaimer | The standard disclaimer, which you must surface to end users (see Disclaimer). |
Inside benchmark | What it means |
|---|---|
| p10, p25, median, p50, p75, p90 | The benchmark: percentiles of total compensation for the role, in US dollars. median and p50 are the same number (see below). |
| confidence, confidence_basis | A depth-of-evidence label, and the statement of what it means (see below). |
| n_obs | The number of Form 990 filings behind the confidence label; on BLS-primary roles, the number of states reporting OEWS wage data. |
| low_confidence, low_confidence_reason | Present only when the cohort has 1–9 comparable filings: true, and a sentence giving the count. |
| revenue_band | The revenue band the organization's revenue falls in. |
| data_vintage | Which data the figure comes from. |
| warning | A note for the user when there is one; otherwise empty. |
| is_bls_primary | true when the role is served from U.S. Bureau of Labor Statistics OEWS wage data rather than from Form 990 filings. |
| geographic_basis, geographic_fallback_reason | Which geography the figure rests on, and why a metro you passed was not used (see below). |
| modelled_figure, no_modelled_figure_reason | At a revenue of 0 there is no modeled figure: modelled_figure is false, every percentile is null, and no_modelled_figure_reason says why. |
| role_filings_note, role_filings_thin | When this role has few or no filings at this revenue, role_filings_thin is true and role_filings_note carries a sentence to report with the figures. |
| base_p10, base_p25, base_median, base_p75, base_p90 | Base compensation (see Component semantics below). |
| bonus_p10, bonus_p25, bonus_median, bonus_p75, bonus_p90 | Bonus and incentive compensation. |
| other_p10, other_p25, other_median, other_p75, other_p90 | Other reportable compensation. |
| retirement_deferred_p10, retirement_deferred_p25, retirement_deferred_median, retirement_deferred_p75, retirement_deferred_p90 | Retirement and deferred compensation. |
| benefits_p10, benefits_p25, benefits_median, benefits_p75, benefits_p90 | Nontaxable benefits. |
| components_basis, components_under_10_filings, components_aged | What the component rows are, and which of them rest on fewer than 10 filings (see Component semantics below). |
| base_pct_nonzero, bonus_pct_nonzero, benefits_pct_nonzero, other_pct_nonzero, retirement_deferred_pct_nonzero, base_n_disclosed, bonus_n_disclosed, benefits_n_disclosed, other_n_disclosed, retirement_deferred_n_disclosed, components_cohort_n | Always null; kept so existing integrations keep their shape (see Component semantics below). |
| bonus_label, bonus_prevalence_pct, bonus_typical_pct | Of executives paid about the served median, the share who received a bonus and the typical bonus as a share of pay (see Component semantics below). |
| filed_titles | The job titles filers most often reported under this role, each with its filing count, plus the role's total filings and number of distinct titles. A help for choosing the role; it does not change the figure. |
| filings_aged | true when the figures were projected to a later date, false when they are as filed. |
| aged_to_date, aged_to_year | The date, and its year, the figures were projected to; null when not projected. This can be earlier than the date you asked for (see money_aging_clamped). |
| aged_from_date, aged_from_year | The date the projection runs from, and its fiscal year. A projected figure starts from Form 990 filings through that fiscal year. Null when not projected. |
| money_aging_factor | The multiplier the projection applied to the as-filed figures; null when not projected. |
| money_aging_base_factor | The multiplier applied to base salary when projected; equal to money_aging_factor when you supply aging_rate. |
| money_aging_base_span_projected | Years of the base salary projection that use a forecast rate. |
| money_aging_forward_vintage | The CBO forecast edition used for forecast years, e.g. "2026-02"; otherwise null. |
| money_aging_source, money_aging_rate_pct | Where the growth rate came from ("corpus-measured-growth" for CauseComp's measured nonprofit pay growth, "user-supplied" for your aging_rate), and the yearly rate you supplied, if you did. |
| money_aging_eci_vintage | The year of the growth table used for the projection; null when not projected. |
| money_aging_clamped, money_aging_requested_year | When the date you asked for is beyond the reach of the measured growth table: a sentence saying which date the figures were projected to instead, and the year you asked for. |
| money_aging_declined, money_aging_refusal | When a projection was asked for and not made: a sentence saying so, and a short code for the reason. Null otherwise. |
| org_type_modifier_applied | true when an org-type adjustment was applied to the figures, otherwise false. |
| org_type_modifier_factor, org_type_modifier_source | When an adjustment was applied: the multiplier, and the sentence describing it that the board report prints. Null otherwise. |
| org_type_modifier_declined | When an org_type was sent and no adjustment was applied: a sentence saying why. Null otherwise. |
| retired_parameter_notice | Present only when the request carried a parameter that is no longer used. The request is answered without it, and this sentence names it. |
Inside input | What it means |
|---|---|
| role, ntee_sector, state, revenue_raw, org_type, ntee_subsector, msa | Each parameter as interpreted: the canonical role, sector and state labels, the subsector in capitals, and null for anything not sent. |
Reading geographic_basis. Which geography the figure rests on: "metro" when the metro you passed contributed, "state" when the state layer did, "national" for a US request. When an msa was passed and is not the basis, geographic_fallback_reason says why: "unknown_msa" (not a code /meta/metros publishes) or "metro_cell_unmeasured" (a published code with no separate estimate) or "msa_not_applicable" (the role is served from BLS OEWS wage data, which has no metro layer, so the parameter was not used); otherwise it is null. The input block echoes every parameter as interpreted, including msa and ntee_subsector. Same keys and values as the workforce endpoint.
Reading confidence. It is a depth-of-evidence label, not a statistical confidence interval, and no interval is published around the figure. It is set by the number of Form 990 filings for this role within a one-third to three-times revenue window; sector and state do not enter that count, and it is counted separately from the comparables set. confidence_basis carries that statement in full on every response, in the same bytes the board PDF and the Excel workbook print, so an API consumer and a board reading the document are told the same thing. It is empty on BLS-primary roles, where confidence is set from the number of states reporting OEWS wage data rather than from a filing count.
Reading median and p50. They are the same number. p50 was added so the percentile ladder reads p10/p25/p50/p75/p90 and the middle rung can be found by position. median is not deprecated and is not going away — it is the original key, every existing integration reads it, and both will continue to be returned. Use whichever you prefer; do not write code that expects only one. The component rows (base, bonus, benefits, other, retirement_deferred) still use _median and have no _p50 form.
Projected figures. Pass age_to_date or
age_to_year to project the figures forward from the filings. A projected response says so in
filings_aged, names the date it was projected to and the multiplier used, and serves the
component rows as null (see Component semantics below). Without either parameter the
figures are as filed and filings_aged is false.
Projected request
curl https://www.causecomp.org/api/v1/executive/benchmark \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "ntee_sector": "Human Services", "state": "CA", "revenue": "$5,000,000", "age_to_date": "2027-06-30"}'
Projected response
{
"benchmark": {
"aged_from_date": "2025-09-07",
"aged_from_year": 2025,
"aged_to_date": "2026-12-31",
"aged_to_year": 2026,
"base_median": 148621,
"base_n_disclosed": null,
"base_p10": 86672,
"base_p25": 111837,
"base_p75": 199693,
"base_p90": 277582,
"base_pct_nonzero": null,
"benefits_median": 7358,
"benefits_n_disclosed": null,
"benefits_p10": 4291,
"benefits_p25": 5536,
"benefits_p75": 9886,
"benefits_p90": 13741,
"benefits_pct_nonzero": null,
"bonus_label": null,
"bonus_median": 2303,
"bonus_n_disclosed": null,
"bonus_p10": 1342,
"bonus_p25": 1733,
"bonus_p75": 3094,
"bonus_p90": 4300,
"bonus_pct_nonzero": null,
"bonus_prevalence_pct": null,
"bonus_typical_pct": null,
"components_aged": true,
"components_basis": "modelled_share",
"components_cohort_n": null,
"components_under_10_filings": [],
"confidence": "High",
"confidence_basis": "Confidence describes the depth of filing evidence for this benchmark. It is not a statistical confidence …",
"data_vintage": "990 data",
"filed_titles": {
"n_distinct_titles": 8684,
"n_filings": 113213,
"titles": [
{
"n_filings": 52581,
"title": "Executive Director"
},
{
"n_filings": 13132,
"title": "CEO"
},
// … 4 more
]
},
"filings_aged": true,
"geographic_basis": "state",
"geographic_fallback_reason": null,
"is_bls_primary": false,
"median": 163697,
"method": "base (role x revenue) + location + NTEE",
"modelled_figure": true,
"money_aging_clamped": "A projection to June 30, 2027 was requested. CauseComp's measured pay growth projection extends to December …",
"money_aging_declined": null,
"money_aging_eci_vintage": 2026,
"money_aging_factor": 1.05530823427,
"money_aging_rate_pct": null,
"money_aging_refusal": null,
"money_aging_requested_year": 2027,
"money_aging_source": "corpus-measured-growth",
"n_obs": 83173,
"no_modelled_figure_reason": null,
"org_type_modifier_applied": false,
"org_type_modifier_declined": null,
"org_type_modifier_factor": null,
"org_type_modifier_source": null,
"other_median": 227,
"other_n_disclosed": null,
"other_p10": 132,
"other_p25": 170,
"other_p75": 304,
"other_p90": 423,
"other_pct_nonzero": null,
"p10": 95465,
"p25": 123183,
"p50": 163697,
"p75": 219951,
"p90": 305741,
"retirement_deferred_median": 3479,
"retirement_deferred_n_disclosed": null,
"retirement_deferred_p10": 2029,
"retirement_deferred_p25": 2618,
"retirement_deferred_p75": 4676,
"retirement_deferred_p90": 6500,
"retirement_deferred_pct_nonzero": null,
"revenue_band": "$5M–$10M",
"role_filings_note": null,
"role_filings_thin": false,
"warning": ""
},
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"input": {
"msa": null,
"ntee_sector": "Human Services",
"ntee_subsector": null,
"org_type": null,
"revenue_raw": "$5,000,000",
"role": "Executive Director / CEO",
"state": "CA"
}
}
Component semantics (September 2026).
The five component rows are modeled shares of the modeled total, so each component
sits at or under its total. Components may not sum exactly to the total. Figures based on fewer than 10 filings are noted.
components_under_10_filings lists the component rows (by name, such as
"other") whose figure rests on fewer than 10 filings; those rows still carry their figures.
components_basis says what the rows are: "modelled_share"
for modeled shares. When no component figures can be given, the rows are
null with components_basis null.
When the request is aged (age_to_year), every component figure is
projected by the same factor as the total and components_aged is
true; it is false when the figures are as filed.
bonus_label, bonus_prevalence_pct and
bonus_typical_pct: of executives paid about the served median, across all
roles and sectors, the share who received a bonus and the typical bonus as a share of pay among
them. null below $150,000, where too few filers disclose a split, and on
aged requests.
*_n_disclosed, *_pct_nonzero and
components_cohort_n remain on the wire for shape stability and are
always null: the rows are no longer drawn from disclosing peers.
The comparables ladders (peer_set_*) are unchanged and remain the
filings’ own percentiles.
POST /workforce/benchmark
Broad-based workforce benchmark from BLS OEWS/ECEC + O*NET.
Professional plan. Each successful call counts as one call against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| role | required | Workforce role label (see /meta/roles). |
| state | required | Two-letter state code. |
| revenue | required | Budget size (amount or band label). |
| ntee_sector | required* | Required in nonprofit mode; omit in private mode. |
| mode | optional | nonprofit (default) or private. |
| level | optional | Seniority tier 1, 2 (default), or 3. |
| naics_code | optional | Industry subsector for finer calibration (private mode). |
| msa | optional | Metro code (see /meta/metros). |
| employees | optional | Headcount, for size-sensitive roles. |
Example request
curl https://www.causecomp.org/api/v1/workforce/benchmark \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Registered Nurse", "state": "IL", "ntee_sector": "Health — Hospitals & Medical", "revenue": "$10,000,000", "level": 2, "mode": "nonprofit"}'
Example response
{
"benchmark": {
"benefits_load_pct": null,
"benefits_p50_usd": null,
"confidence": "High",
"data_vintage": "BLS OEWS May 2025 (aged to Sep 2026)",
"geographic_basis": "state",
"geographic_fallback_reason": null,
"incentive_incidence": null,
"incentive_p25_pct": null,
"incentive_p25_usd": null,
"incentive_p50_pct": null,
"incentive_p50_usd": null,
"incentive_p75_pct": null,
"incentive_p75_usd": null,
"is_bls_primary": true,
"is_national": false,
"major_group_line": "",
"median": 104295,
"method": "BLS OEWS primary — BLS OEWS May 2025 US national (official) + ECI aging + state ratio + industry adjustment + …",
"mode": "nonprofit",
"n_obs": 51,
"onet_attribution": {
"license": "CC BY 4.0",
"license_link_text": "CC BY 4.0",
"license_url": "https://creativecommons.org/licenses/by/4.0/",
"modification_notice": null,
"modified": false,
"release": "31.0",
"text": "This page includes information from the O*NET 31.0 Database by the U.S. Department of Labor, Employment and …"
},
"onet_covers": [],
"onet_reported_titles": [
"Certified Operating Room Nurse (CNOR)",
"Charge Nurse",
// … 8 more
],
"p10": 73707,
"p25": 85884,
"p50": 104295,
"p75": 120118,
"p90": 146975,
"revenue_band": "$10M–$25M",
"role_description": "Assess patient health problems and needs, develop and implement nursing care plans, and maintain medical …",
"seniority_tier": "Mid (Tier II)",
"total_cash_p25_usd": null,
"total_cash_p50_usd": null,
"total_cash_p75_usd": null,
"total_comp_p50_usd": null,
"warning": ""
},
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"input": {
"employees": null,
"level": 2,
"mode": "nonprofit",
"msa": null,
"naics_code": null,
"ntee_sector": "Health — Hospitals & Medical",
"revenue_raw": "$10,000,000",
"role": "Registered Nurse",
"state": "IL"
}
}
This page includes information from the O*NET 31.0 Database by the U.S. Department of Labor, Employment and Training Administration (USDOL/ETA). Used under the CC BY 4.0 license. O*NET® is a trademark of USDOL/ETA. CauseComp (RB Consulting Services, LLC) has modified all or some of this information. USDOL/ETA has not approved, endorsed, or tested these modifications.
What comes back
| Field | What it means |
|---|---|
| benchmark | The figures, described in the next table. |
| input | Your inputs as interpreted. |
| disclaimer | The standard disclaimer, which you must surface to end users. |
Inside benchmark | What it means |
|---|---|
| p10, p25, median, p50, p75, p90 | Percentiles of pay for the role, in US dollars. median and p50 are the same number. |
| confidence, n_obs | A depth-of-evidence label, and the count behind it (for roles served from OEWS wage data, the number of states reporting). |
| revenue_band | The revenue band the organization's revenue falls in. |
| data_vintage | Which wage data the figure comes from, and the date it has been brought forward to. |
| warning | A sentence for the user, for example when a metro you passed did not become the basis; otherwise empty. |
| seniority_tier | The seniority tier the figure is for (from level). |
| mode | nonprofit or private, as served. |
| is_bls_primary, is_national | Whether the role is served from OEWS wage data, and whether the figure is a national one rather than one for your state. |
| geographic_basis, geographic_fallback_reason | Which geography the figure rests on, and why a metro you passed was not used. Same keys and values as the executive endpoint. |
| role_description, onet_reported_titles, onet_covers, major_group_line | What the job is: O*NET's description, the job titles O*NET reports for it, the detailed occupations a broad occupation group covers, and, for a broad group with no O*NET entry, a written line instead. |
| onet_attribution | The O*NET credit, present whenever the response carries O*NET text. |
| soc_code, soc_title, soc_codes_covered | The BLS occupation the figures are priced on, and every detailed occupation a combined role covers. |
| role_notes | Notes on choosing this role, when it has any; otherwise an empty list. |
| label_deprecation | Present only when the request named a retired label: the label sent, the current label, and a note. The figures are the current label's. |
| incentive_p25_pct, incentive_p50_pct, incentive_p75_pct, incentive_p25_usd, incentive_p50_usd, incentive_p75_usd, total_cash_p25_usd, total_cash_p50_usd, total_cash_p75_usd, incentive_incidence, benefits_load_pct, benefits_p50_usd, total_comp_p50_usd | Incentive and benefits-load fields, populated for roles with ECEC incentive coverage and null otherwise. |
Inside input | What it means |
|---|---|
| role, ntee_sector, state, revenue_raw, mode, msa, naics_code, level, employees | Each parameter as interpreted: level after its default, and null for anything not sent or not readable. |
POST /comparables
The §4958 comparables set for the same inputs as an executive benchmark. It is drawn
separately from the modeled figure and does not produce it. This is the compliance layer for a board file.
You can also name the organizations yourself (organizations): the response is then
what those organizations filed, not a peer set CauseComp selected.
Professional plan (the §4958 comparables fence). Each successful call counts as one call against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| role | required | Executive role label, as for /executive/benchmark. Officer role, a list of roles, or 'all'. Required when organizations are supplied. |
| ntee_sector | required* | NTEE sector label. Required unless organizations is given. |
| state | required* | Two-letter state code, or US. Required unless organizations is given; with it, it sets which rows count as in-state. |
| revenue | required* | Annual budget size (amount or band label). Required unless organizations is given. |
| ntee_subsector | optional | Three-character NTEE subsector code (e.g. P20). |
| peer_sectors | optional | A sector label, a list of labels, or "all": which sectors the peers are ranked toward, and how composition.in_sector is counted. It does not change the benchmark, which stays for ntee_sector. An unrecognized label returns a correction carrying the valid sectors. |
| select_on | optional | Which comparables set to return: "role" (the default) chooses organizations on their filings for this role; "ceo" chooses them on their Executive Director / CEO filings and lists each one's filing for this role where it has one, so it can list fewer. For Executive Director / CEO the two are the same. Not accepted with organizations. |
| organizations, eins | optional | Organizations to report on, by name or EIN, in any mix. Supplying this returns what those organizations filed in the last five years instead of a modelled peer cohort; an organization with no filing in that window is listed as unresolved, with the reason. You can name up to 100 organizations in one request. Split a larger list into several requests. (eins is accepted as another name for the same list.) |
| city | optional | Optional city, used to tell same-named organizations apart. |
| include_ein | optional | Return each organization's EIN on its row. |
Example request
curl https://www.causecomp.org/api/v1/comparables \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "ntee_sector": "Human Services", "state": "CA", "revenue": "$5,000,000"}'
Example response
{
"comparables": [
{
"base": null,
"bonus": null,
"city": "BEVERLY HILLS",
"disclosure_basis": "Total only (Form 990 Part VII or 990-EZ)",
"fiscal_year": 2025,
"mission": null,
"mission_display": null,
"mission_display_classification": null,
"mission_display_source": null,
"mission_display_year": null,
"mission_reason": null,
"mission_source": null,
"nontaxable": null,
"ntee_code": "P60",
"ntee_description": "Emergency Assistance",
"org": "ELEVATE HOPE INC",
"other": null,
"placeholder_flag": null,
"retirement_deferred": null,
"revenue": 5007995,
"sector": "Human Services",
"state": "CA",
"title": "Executive Director",
"total_comp": 111000,
"website_url": null
},
{
"base": null,
"bonus": null,
"city": "WALNUT CREEK",
"disclosure_basis": "Total only (Form 990 Part VII or 990-EZ)",
"fiscal_year": 2024,
"mission": "(the filer's text, 173 characters)",
"mission_display": "(the filer's text, 173 characters)",
"mission_display_classification": null,
"mission_display_source": null,
"mission_display_year": null,
"mission_reason": "disclosed",
"mission_source": "MissionDesc",
"nontaxable": null,
"ntee_code": "P73",
"ntee_description": "Group Homes",
"org": "FULL CIRCLE OF CHOICES",
"other": null,
"placeholder_flag": false,
"retirement_deferred": null,
"revenue": 4971927,
"sector": "Human Services",
"state": "CA",
"title": "Executive Dir.",
"total_comp": 124770,
"website_url": null
},
// … 18 more
],
"composition": {
"evidence": {
"in_sector_n": 20,
"in_state_n": 20,
"listed_n": 20,
"national_pool_n": 37041
},
"filing_window_from": "202110",
"filing_window_years": 3,
"in_sector": 20,
"in_sector_n": 20,
"in_state": 20,
"n": 20,
"n_national": 37041,
"ntee_sector": "Human Services",
"peer_set_basis": "modelled",
"requested": 20,
"select_on": "role",
"state": "CA"
},
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"peer_set_ladders": {
"base": {
"field": "base",
"n": 10,
"peer_set_p10": 157440.0,
"peer_set_p25": 165913.25,
"peer_set_p50": 189926.0,
"peer_set_p75": 199861.25,
"peer_set_p90": 251750.89999999997
},
"total_comp": {
"field": "total_comp",
"n": 20,
"peer_set_p10": 109961.0,
"peer_set_p25": 119811.0,
"peer_set_p50": 162560.5,
"peer_set_p75": 207219.75,
"peer_set_p90": 234709.6
}
}
}
What comes back
| Field | What it means |
|---|---|
| comparables | The organizations and what each reported (next table). |
| composition | How the set is made up (see below). Always show it alongside the list. |
| peer_set_ladders | P10 to P90 across the rows listed, for total_comp and for base, each with its own count n (a filer that reports only a total has no base). Keyed peer_set_p10 … peer_set_p90 so they are never confused with the benchmark's own percentiles. Absent on a set spanning several roles. |
| supplied | Only when you named the organizations: how many you asked for, how many were found, how many rows came back, and each one not resolved (unresolved, with the reason), matched more than once (ambiguous) or without a filing for the role (role_not_held). |
| widened | Only when the set has no row for the role: rows for that role from the same state and from other states, as two separate blocks beside the set. They are never merged into it. |
| disclaimer | The standard disclaimer, which you must surface to end users. |
Each row of comparables | What it means |
|---|---|
| org, city, state, ein | The organization as it filed (ein only with include_ein). |
| fiscal_year, title, role | The filing's year, the officer's title as reported, and the role it counts under. |
| sector, ntee_code, ntee_description | The organization's NTEE sector, its subsector code and that code's description (null when the filing carries no code). |
| revenue, total_comp | The organization's revenue and the officer's total reported compensation, in US dollars. |
| base, bonus, other, retirement_deferred, nontaxable | The reported components, where the filing itemizes them; null where it reports only a total. |
| disclosure_basis | Which kind of report the row comes from: itemized components, or a total only. |
| part_year | True when the filing's title indicates the officer served part of the fiscal year; the compensation shown covers that period only and is not annualized. |
| mission, mission_display, mission_display_source | Each row also carries the organization's mission as it filed it on its Form 990 (mission) and mission_display: that text, or, where the filer wrote only a pointer such as "See Schedule O", the text it pointed to, with mission_display_source naming where it came from. |
| mission_source, mission_reason, placeholder_flag, mission_display_year, mission_display_classification, website_url | More about the mission text: the form field it came from, whether a mission was disclosed, whether the filed text is only a pointer, the tax year of text taken from another year's filing, the NTEE classification shown when no text exists (a classification, not a description), and the organization's website where one is on file. |
Inside composition | What it means |
|---|---|
| n, requested | How many organizations are listed, and how many were asked for; fewer listed than asked means the data held fewer. |
| below_three | Present, and true, only when fewer than three organizations are listed (none, one or two). The rows are still returned; a board report or workbook is not produced from a set this small. |
| state, in_state | The requested state, and how many listed organizations are in it. |
| ntee_sector, in_sector, in_sector_n, sectors | The benchmark's sector; how many listed organizations are in the set the peers were ranked toward (sectors, present only when you passed peer_sectors); and how many are in the benchmark's own sector. |
| n_national | The number of organizations the set can draw from nationally for this role and size. It is a count of organizations, not filings, and it does not narrow by sector. Always report it whenever you report in_state. |
| evidence | The same four counts together: national_pool_n, listed_n, in_sector_n, in_state_n. |
| filing_window_years, filing_window_from | Each organization contributes filings from its own most recent filing_window_years years, counted back from its latest return. filing_window_from is the earliest month (YYYYMM) an organization's latest return may end and still be included. |
| peer_set_basis, peer_set_basis_note | Which kind of set this is: "modelled" when CauseComp selected it, "caller-supplied" when you named the organizations (with a sentence saying so). |
| select_on | Which set this is, "role" or "ceo" (see the request parameter). Absent when you named the organizations. |
| local_mix_kept | Present, and true, only when the set was drawn by the local mix described under Reading composition. |
| n_orgs, n_rows, roles_requested, multi_role | Only when you named the organizations: how many were found, how many rows came back, the roles asked for, and whether more than one role was asked for. |
Inside peer_set_ladders | What it means |
|---|---|
| total_comp, base | Each a ladder: field, n, and peer_set_p10 to peer_set_p90. |
Inside supplied | What it means |
|---|---|
| requested, resolved_orgs, rows | How many organizations you named, how many were found, and how many rows came back. |
| unresolved, ambiguous, role_not_held | The organizations not found (each with its reason), those that matched more than one organization, and those with no filing for the role. |
Reading composition. State and sector favor
organizations rather than restrict the set to them, so a peer set can include organizations from other states where in-state
filings are few. When local_mix_kept is true, the set was drawn up to half from the same NTEE subsector
nationwide and the rest from the same NTEE major group, organizations in the requested state first.
An out-of-state filing in the same role, sector and revenue band is a valid comparable. Report n_national
whenever you report in_state.
Organizations you name. With organizations,
role may be one role, a list of roles, or "all". A set spanning several roles
returns no percentile ladder: peer_set_ladders is absent, because percentiles across different roles
describe no single group.
Named-organizations request
curl https://www.causecomp.org/api/v1/comparables \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "state": "CA", "organizations": ["770448301", "No Such Organization Anywhere"]}'
Named-organizations response
{
"comparables": [
{
"base": 355000,
"bonus": null,
"city": "OXNARD",
"fiscal_year": 2024,
"mission": "(the filer's text, 193 characters)",
"mission_display": "(the filer's text, 193 characters)",
"mission_display_classification": null,
"mission_display_source": null,
"mission_display_year": null,
"mission_reason": "disclosed",
"mission_source": "MissionDesc",
"nontaxable": null,
"ntee_code": "P29",
"ntee_description": "Thrift Shops",
"org": "GOODWILL INDUSTRIES OF SANTA BARBARA AND VENTURA COUNTIES",
"other": null,
"part_year": false,
"placeholder_flag": false,
"retirement_deferred": 17750,
"revenue": 45498855,
"role": "Executive Director / CEO",
"sector": "Human Services",
"state": "CA",
"title": "President & Ceo",
"total_comp": 372750,
"website_url": null
}
],
"composition": {
"below_three": true,
"filing_window_from": "202110",
"filing_window_years": 5,
"in_state": 1,
"multi_role": false,
"n_orgs": 1,
"n_rows": 1,
"peer_set_basis": "caller-supplied",
"peer_set_basis_note": "These organizations were named in the request. CauseComp reported what each one filed on its Form 990 and did …",
"requested": 2,
"roles_requested": [
"Executive Director / CEO"
],
"state": "CA"
},
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"peer_set_ladders": {
"base": {
"field": "base",
"n": 1,
"peer_set_p10": 355000.0,
"peer_set_p25": 355000.0,
"peer_set_p50": 355000.0,
"peer_set_p75": 355000.0,
"peer_set_p90": 355000.0
},
"total_comp": {
"field": "total_comp",
"n": 1,
"peer_set_p10": 372750.0,
"peer_set_p25": 372750.0,
"peer_set_p50": 372750.0,
"peer_set_p75": 372750.0,
"peer_set_p90": 372750.0
}
},
"supplied": {
"ambiguous": [],
"requested": 2,
"resolved_orgs": 1,
"role_not_held": [],
"rows": 1,
"unresolved": [
{
"input": "No Such Organization Anywhere",
"reason": "no_match"
}
]
}
}
POST /board-report
The board report as a PDF: the same document the website's board report produces for these inputs, returned inside a JSON response.
With organizations, the comparables section, its P10-P90 ladder and composition come from what those organizations filed; composition then carries no national pool, and supplied lists any organization that could not be listed, with the reason.
Professional plan (the same §4958 comparables fence as /comparables). Each
successful call counts as one call against the daily quota; no report credit is used.
| Parameter | Req? | Description |
|---|---|---|
| role | required | Executive role label the report is for. |
| ntee_sector | required | NTEE sector label. |
| state | required | Two-letter state code, or US. An unrecognized value returns a correction listing the valid codes. |
| revenue | required | Annual budget size (amount or band label). |
| org | optional | The organization's name as it should appear on the report cover. |
| org_type, ntee_subsector, msa | optional | As for /executive/benchmark; the document says whether an org-type adjustment was applied. |
| peer_sectors | optional | As for /comparables: which sectors the listed peers are ranked toward. |
| select_on | optional | As for /comparables. |
| age_to_date, age_date | optional | Project the report's figures to this date (YYYY-MM-DD), as for /executive/benchmark. age_date is accepted as another name. |
| age_to_year | optional | Project to 31 December of this year; ignored when a date is given. |
| aging_rate, age_rate | optional | A yearly growth rate in percent to use instead of the measured growth rate. age_rate is accepted as another name. |
| delivery | optional | Set to "link" to receive a download link instead of the PDF bytes: the response then carries download_url and download_expires_at in place of pdf_base64. |
| organizations, eins | optional | Organizations to report on, by name or EIN, in any mix. Supplying this returns what those organizations filed in the last five years instead of a modelled peer cohort; an organization with no filing in that window is listed as unresolved, with the reason. You can name up to 100 organizations in one request. Split a larger list into several requests. (eins is accepted as another name for the same list.) |
| city | optional | Optional city, used to tell same-named organizations apart. |
| include_ein | optional | Return each organization's EIN on its row. |
| without_comparables | optional | See below. |
Example request
curl https://www.causecomp.org/api/v1/board-report \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "ntee_sector": "Human Services", "state": "CA", "revenue": "$5,000,000", "org": "Example Organization"}'
Example response
{
"composition": {
"evidence": {
"in_sector_n": 20,
"in_state_n": 20,
"listed_n": 20,
"national_pool_n": 37041
},
"filing_window_from": "202110",
"filing_window_years": 3,
"in_sector": 20,
"in_sector_n": 20,
"in_state": 20,
"n": 20,
"n_national": 37041,
"ntee_sector": "Human Services",
"requested": 20,
"select_on": "role",
"state": "CA"
},
"content_type": "application/pdf",
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"filename": "causecomp_board_report.pdf",
"pdf_base64": "(22336 base64 characters)",
"sha256": "67025abba2e81cc9bb1aefbed21a310484f721bf42ee427f2be4e1d9d1469418",
"size": 16750
}
What comes back
| Field | What it means |
|---|---|
| pdf_base64 | The PDF itself, base64-encoded (described, not printed, in the example above). |
| download_url, download_expires_at | Only with delivery "link", in place of pdf_base64: a link to the PDF, valid for 24 hours and only for the CauseComp account that ran the report, and the time it expires (UTC). |
| filename, content_type, size, sha256 | A file name to save it under, application/pdf, its size in bytes, and its SHA-256 hash. |
| composition | The same composition block as /comparables, for the peers the report lists. State it alongside the report. |
| without_comparables | Present, and true, only on a report produced without a comparables set (see below). |
| supplied | Only when you named the organizations: how many you asked for, how many were found, how many rows came back, and each one not resolved (unresolved, with the reason), matched more than once (ambiguous) or without a filing for the role (role_not_held). |
| disclaimer | The standard disclaimer, which you must surface to end users. |
Inside composition | What it means |
|---|---|
| n, requested, state, in_state, ntee_sector, in_sector, in_sector_n, sectors, n_national, evidence, filing_window_years, filing_window_from, peer_set_basis, peer_set_basis_note, select_on, below_three, n_orgs, n_rows, roles_requested, multi_role | As for /comparables. |
| n_part_year | Only when you named the organizations and at least one listed row is part year: how many are. |
Inside supplied | What it means |
|---|---|
| requested, resolved_orgs, rows, unresolved, ambiguous, role_not_held | As for /comparables. |
A request with no comparable filings, with none in the requested sector, or with fewer
than three organizations to list is refused rather than rendered: HTTP 422 with code
no_comparables, no_sector_match or below_three.
Each carries renderable_without_comparables and a question. An unrecognized
role, sector or state returns a correction carrying the valid values.
without_comparables(request, boolean): set to true, after a refusal that offers it, to request a board report without a comparables section; the report then says why and omits the comparables section.renderable_without_comparables(response, boolean): true when this request can produce a board report without a comparables set.
POST /filings/lookup
Return rows of Form 990 compensation filings selected by the filters you pass, 20 rows a page in a fixed
order. This is a data lookup, not a comparables set: the response states which filters selected the rows. There is no
minimum number of rows: a filter that matches one filing returns that filing, and one that matches none returns
matched 0.
Professional plan. Each successful call counts as one call against the daily quota, and every row returned
counts against a separate limit of 200 rows of filing data per account per day, reported in
row_meter. A page that would pass the limit returns the rows up to it, with
row_limit_message; once the limit is reached, calls are refused with
row_quota_exceeded until 00:00 UTC.
| Parameter | Req? | Description |
|---|---|---|
| role | optional | Filed role label to select rows for, e.g. 'Executive Director / CEO'. An unrecognized label returns a correction listing every accepted label. |
| state | optional | Two-letter US state code; selects rows filed from that state. 'US' applies no state filter. Accepts the codes list_states returns. |
| metro | optional | Metro-area (CBSA) code, e.g. '16980'. Selects rows whose filed city is placed in that metro area; the response carries a note on the filings this filter cannot place. |
| revenue_band | optional | Organization revenue band label, e.g. '$5M–$10M' (the same labels get_executive_benchmark accepts). |
| revenue_min | optional | Lowest organization revenue to include, in US dollars. |
| revenue_max | optional | Highest organization revenue to include, in US dollars. |
| ntee_sector | optional | NTEE sector label, one of those list_sectors returns. |
| ntee_subsector | optional | Three-character NTEE subsector code, e.g. 'P20'. Filings that carry no subsector code are not selected by this filter. |
| fiscal_year_from | optional | Earliest fiscal year to include. |
| fiscal_year_to | optional | Latest fiscal year to include. |
| page | optional | Page number, starting at 1. Each page holds up to 20 rows. |
A filter name not in this table, or a value the filter does not recognize, returns a
correction (HTTP 422, unrecognized_filter) naming the filter and carrying the accepted values, never an empty result.
Example request
curl https://www.causecomp.org/api/v1/filings/lookup \
-H "Authorization: Bearer cc_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "Executive Director / CEO", "state": "CA", "ntee_sector": "Human Services", "revenue_band": "$5M–$10M", "fiscal_year_from": 2023}'
Example response
{
"disclaimer": "CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. …",
"matched": 187,
"page": 1,
"page_size": 20,
"pages": 10,
"returned": 20,
"row_meter": {
"limit": 200,
"remaining": 180,
"used": 20
},
"rows": [
{
"base": null,
"bonus": null,
"city": "GROVER BEACH",
"disclosure_basis": "Total only (Form 990 Part VII or 990-EZ)",
"fiscal_year": 2025,
"nontaxable": null,
"ntee_code": "P85",
"ntee_description": "Homeless Centers",
"ntee_sector": "Human Services",
"org": "5CITIES HOMELESS COALITION",
"other": null,
"part_year": false,
"retirement_deferred": null,
"revenue": 5409642,
"role": "Executive Director / CEO",
"state": "CA",
"title": "Executive Director",
"total_comp": 126684
},
{
"base": 334173,
"bonus": null,
"city": "WHITTIER",
"disclosure_basis": "Schedule J, Part II (components itemized)",
"fiscal_year": 2025,
"nontaxable": null,
"ntee_code": "P32",
"ntee_description": "Foster Care",
"ntee_sector": "Human Services",
"org": "A GREATER LOVE FOSTER FAMILY AGENCY INC",
"other": null,
"part_year": false,
"retirement_deferred": null,
"revenue": 9197695,
"role": "Executive Director / CEO",
"state": "CA",
"title": "Executive Dir.",
"total_comp": 334173
},
// … 18 more
],
"selected_by": {
"fiscal_year_from": 2023,
"ntee_sector": "Human Services",
"revenue_band": "$5M–$10M",
"role": "Executive Director / CEO",
"state": "CA"
},
"withheld": 0
}
What comes back
| Field | What it means |
|---|---|
| rows | This page's filings (next table). |
| matched, page, page_size, pages | How many filings the filters matched in all, this page's number, the page size, and the number of pages. |
| returned, withheld | How many rows this response carries, and how many of this page's rows were held back by the daily row limit. |
| selected_by | The filters that selected the rows, as interpreted. |
| metro_notice | Only with metro: a note on the filings the metro filter cannot place. |
| row_meter | The account's row limit for the day, rows used and rows remaining. |
| row_limit_message | Present when this response reached the daily row limit. |
| disclaimer | The standard disclaimer, for any answer built from these rows. |
Each row of rows | What it means |
|---|---|
| org, city, state, fiscal_year | The organization and the filing's year. |
| role, title | The role the row counts under, and the officer's title as reported. |
| ntee_sector, ntee_code, ntee_description | The organization's NTEE sector, subsector code and that code's description. |
| revenue, total_comp, base, bonus, other, retirement_deferred, nontaxable | The organization's revenue and the officer's reported compensation, in US dollars; components are null where the filing reports only a total. |
| disclosure_basis | Which kind of report the row comes from: itemized components, or a total only. |
| part_year | True when the filing's title indicates the officer served part of the fiscal year; the compensation shown covers that period only and is not annualized. |
Inside selected_by | What it means |
|---|---|
| role, state, metro, revenue_band, revenue_min, revenue_max, ntee_sector, ntee_subsector, fiscal_year_from, fiscal_year_to | Each filter you passed, as interpreted. Filters you did not pass are absent. |
Inside row_meter | What it means |
|---|---|
| limit, used, remaining | The day's row limit, rows returned to the account today including this response, and rows left. |
GET /organizations/find
Find nonprofit organizations by name in the comparables index (IRS Form 990 filers with officer
compensation on record in the last five years) and get each one's EIN, to pass as organizations
to /comparables. Returns up to 20 matches in alphabetical order, with no ranking.
Professional plan (the §4958 comparables fence). Not metered: lookups do not count against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| name | required | The organization's name. Every word of three or more letters in it appears in each match's indexed name; case does not matter. |
| state | optional | Two-letter state code to narrow a common name. An unrecognized value returns the valid codes. |
Example request
GET /api/v1/organizations/find?name=goodwill+industries&state=CA
Example response
{
"n": 8,
"organizations": [
{
"city": "SANTA ANA",
"ein": "951644018",
"latest_filing_year": 2024,
"mission": "(the filer's text, 113 characters)",
"mission_display": "(the filer's text, 113 characters)",
"mission_display_classification": null,
"mission_display_source": null,
"mission_display_year": null,
"mission_reason": "disclosed",
"mission_source": "MissionDesc",
"name": "GOODWILL INDUSTRIES OF ORANGE COUNTY CA",
"ntee_sector": "Employment",
"placeholder_flag": false,
"revenue_band": "$100M–$500M",
"state": "CA",
"website_url": null
},
{
"city": "SANTA ROSA",
"ein": "942237862",
"latest_filing_year": 2025,
"mission": "(the filer's text, 83 characters)",
"mission_display": "(the filer's text, 83 characters)",
"mission_display_classification": null,
"mission_display_source": null,
"mission_display_year": null,
"mission_reason": "disclosed",
"mission_source": "MissionDesc",
"name": "GOODWILL INDUSTRIES OF REDWOOD EMPIRE",
"ntee_sector": "Employment",
"placeholder_flag": false,
"revenue_band": "$25M–$50M",
"state": "CA",
"website_url": null
},
// … 6 more
],
"truncated": false
}
What comes back
| Field | What it means |
|---|---|
| organizations, n | The matches (next table) and how many there are. |
| truncated | true when more than 20 matched; a longer name or a state narrows the list. |
| message | Only when nothing matched: a sentence saying so. |
| unclassified_sector_note | Only when a listed organization has no NTEE code on file: a sentence saying the user should be asked which sector their organization works in. |
| Each match | What it means |
|---|---|
| name, ein, city, state | The organization and its EIN. |
| ntee_sector, revenue_band, latest_filing_year | Its NTEE sector, its revenue band and the year of its latest filing. |
| sector_unclassified | Only on an organization with no NTEE code on file: true, and its ntee_sector is null. Ask the user which sector it works in; there is no benchmark for an unclassified sector. |
| mission, mission_display, mission_display_source, mission_source, mission_reason, placeholder_flag, mission_display_year, mission_display_classification, website_url | The mission fields, as on a /comparables row. |
GET /meta/exec_roles
Valid executive role labels. Optional
?search= matches role labels and the officer titles filers report on Form 990, best match first, and resolves fuzzy input to a canonical label
before you benchmark (avoids an unrecognized_role error). Professional plan. Not metered: lookups do not count against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| search | optional | Case-insensitive search. Matches role labels and the officer titles filers report on Form 990, best match first. |
| Field | What it means |
|---|---|
| roles | The matching labels. |
| role_details | On a search: one row per label in roles, in the same order, saying what matched. |
| Field | What it means |
|---|---|
| role | The label to pass to the benchmark. |
| matched_on, matched_term | On a search: what matched (label or filed_title, a title filers report on Form 990) and the text that matched. |
Example request
GET /api/v1/meta/exec_roles?search=chief
Example response
{
"roles": [
"Chief Administrative Officer",
"Chief Compliance Officer",
// … 15 more
]
}
GET /meta/roles
Valid workforce role labels, with the same optional ?search= filter. Professional plan. Not metered: lookups do not count against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| search | optional | Case-insensitive search. Matches the role label, the BLS SOC code and title, common job titles and O*NET reported titles, then O*NET alternate titles, best match first. |
| Field | What it means |
|---|---|
| roles | The matching labels. |
| role_details | One row per label in roles, in the same order: the role's BLS occupation and, on a search, what matched. |
| Field | What it means |
|---|---|
| role | The label to pass to the benchmark. |
| soc_code, soc_title | The BLS occupation code and title the role is priced on. |
| soc_codes_covered | On a search: every detailed BLS occupation the role covers (more than one for a combined role). |
| matched_on, matched_term | On a search: what matched (label, soc_code, soc_title, alias, legacy_label, onet_reported_title or onet_alternate_title) and the text that matched. |
| label_deprecation | On a search for a retired label: the label sent, the current label, and a note. |
Example request
GET /api/v1/meta/roles?search=nurse
Example response
{
"roles": [
"Nurse Practitioner",
"Registered Nurse",
// … 4 more
]
}
GET /meta/metros
Metro areas (MSAs) for a state, largest employment first — the valid
msa codes a benchmark call can pass.
?state= is required.
Professional plan. Not metered: lookups do not count against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| state | required | Two-letter state code. An empty or unrecognized value returns an empty list. |
| Field | What it means |
|---|---|
| metros | The metro areas, largest employment first. |
| Each metro | What it means |
|---|---|
| code, name | The code to pass as msa, and the metro's name. |
Example request
GET /api/v1/meta/metros?state=IL
Example response
{
"metros": [
{
"code": "16980",
"name": "Chicago-Naperville-Elgin, IL-IN"
},
{
"code": "37900",
"name": "Peoria, IL"
},
// … 6 more
]
}
GET /meta/states
Valid state codes for a benchmark call. US is a member of
the list: it means the national benchmark with no state adjustment. No parameters. Professional plan. Not metered: lookups do not count against the daily quota.
| Field | What it means |
|---|---|
| states | The valid codes. |
Example request
GET /api/v1/meta/states
Example response
{
"states": [
"US",
"AL",
// … 50 more
]
}
GET /meta/sectors
Valid NTEE sector labels for the ntee_sector input. No parameters. sectors_detail pairs each label with its NTEE major-group letter (sorted by code); pass the bare label as the ntee_sector input.
Professional plan. Not metered: lookups do not count against the daily quota.
| Field | What it means |
|---|---|
| sectors | The valid labels. |
| sectors_detail | Each label with its NTEE major-group letter. |
| Each entry | What it means |
|---|---|
| code, label | The major-group letter and the label. |
Example request
GET /api/v1/meta/sectors
Example response
{
"sectors": [
"Arts, Culture & Humanities",
"Civil Rights",
// … 24 more
],
"sectors_detail": [
{
"code": "A",
"label": "Arts, Culture & Humanities"
},
{
"code": "B",
"label": "Education"
},
// … 24 more
]
}
GET /meta/methodology
The published methodology: the site's own Methodology page, split into its sections. Professional plan. Not metered: lookups do not count against the daily quota.
Its Data source section names the fiscal years of the Form 990 filings the executive model is built from.
| Parameter | Req? | Description |
|---|---|---|
| section | optional | Return only the sections whose heading contains this text (case does not matter). A heading with no text of its own returns the sections beneath it. An unknown section returns an empty list, the available headings and a message, not an error. |
| Field | What it means |
|---|---|
| source | The page the sections come from: /methodology. |
| sections | The sections (next table). |
| available, message | Only with section: every heading on the page, and a sentence when the match needs one. |
| Each section | What it means |
|---|---|
| heading, level, text | The section's heading, its heading level and its text. |
Example request
GET /api/v1/meta/methodology?section=Reading+the+numbers
Example response
{
"available": [
"Executive Compensation 990",
"Data source",
// … 9 more
],
"message": "",
"sections": [
{
"heading": "Reading the numbers",
"level": 2,
"text": "P25 / Median / P75 describe where pay falls across comparable organizations — a market range, not a …"
}
],
"source": "/methodology"
}
GET /meta/role_about
The role description CauseComp shows beside a benchmark: the same text as the About this role panel on the site, as data.
Professional plan. Not metered: lookups do not count against the daily quota.
| Parameter | Req? | Description |
|---|---|---|
| product | required | executive or workforce. |
| role | required | an exact label from /meta/exec_roles or /meta/roles. |
Errors & limits
Every failure returns the same envelope — never an HTML page or a stack trace:
{ "error": { "code": "...", "message": "...", /* optional hints */ } }
| HTTP | code | When |
|---|---|---|
| 400 | bad_request | A request the endpoint cannot read, such as named organizations with no role, or board-report inputs that are missing. |
| 401 | unauthorized | Missing, invalid, expired, or revoked credential. |
| 403 | forbidden | Owner lacks the Professional plan (carries an upgrade_url); comparables also need the Professional §4958 fence. |
| 422 | validation_error | Bad or missing input (unparseable revenue, absent required field). |
| 422 | unrecognized_role | Role not recognized; carries suggestions. |
| 422 | unrecognized_sector | Sector label not recognized; carries the valid sectors. |
| 422 | unrecognized_state | State code not recognized; carries the valid codes (see /meta/states). |
| 422 | too_many_peer_sectors | More peer_sectors than are allowed; carries the limit and the valid sectors. |
| 422 | unrecognized_filter | /filings/lookup only: a filter or value not recognized; carries the accepted values. |
| 422 | insufficient_comparables | Recognized cohort with zero comparable filings; carries data-backed suggested_fallback_roles. |
| 422 | no_data | No figure is available for this request, for example a workforce role that is not benchmarked or has been renamed (a renamed role carries suggestions). |
| 422 | select_on_with_organizations | select_on was sent with organizations; the set choice applies only to a set CauseComp selects. |
| 422 | role_matched_reference_retired | /comparables only: role_matched_reference is no longer offered. The comparables set is now chosen on this role's filings by default; select_on "ceo" returns the set chosen on Executive Director / CEO filings. |
| 422 | no_comparables, no_sector_match, below_three, no_named_organization_listed | /board-report only: the report is refused (see that section). |
| 429 | rate_limited | Burst limit exceeded (120 requests per minute per credential). |
| 429 | quota_exceeded | Daily account quota reached (carries limit). |
| 429 | row_quota_exceeded | /filings/lookup only: the daily row limit is reached (carries limit). |
| 500 | forecast_error, internal_error | Something failed on our side; the request can be retried. |
"Unknown" is no longer a sector label. A request that sends it gets the unrecognized_sector correction with the valid sectors, plus retired_sector: true and a message saying why.
Daily quota
Each account may make 250 calls per day, across all of its API keys and connector
sign-ins together; the meter resets at 00:00 UTC. The POST endpoints count; the lookups
(/meta/* and /organizations/find) do not.
Only successful calls count: a request refused for bad input or by a plan fence does not. On the call after the limit:
{ "error": { "code": "quota_exceeded",
"message": "Daily query limit of 250 reached for this account. It resets at 00:00 UTC.",
"limit": 250 } }
On a Consultant subscription the limit is 1,000 calls per day instead of 250. Everything else above applies the same way.
/filings/lookup also has a row limit: 200 rows of
filing data per account per day, beside the call quota (see that section).
Structured 422s you can branch on
An unrecognized role comes back with "did you mean" suggestions:
{
"error": {
"code": "unrecognized_role",
"message": "Unrecognized role 'Chief Finance Officer'. Choose a listed executive role.",
"requested_role": "Chief Finance Officer",
"suggestions": [
"Chief Administrative Officer",
"Chief Compliance Officer",
// … 3 more
]
}
}
A recognized cohort with no comparable filings returns data-backed fallback roles (with their observation counts) instead of an ungrounded number:
{
"error": {
"code": "insufficient_comparables",
"low_confidence_below": 10,
"message": "No comparable Schedule-J filings for 'Chief Data Officer' in Human Services at <$500K. Try a broader officer …",
"n_obs": 0,
"requested": {
"ntee_sector": "Human Services",
"revenue_band": "<$500K",
"role": "Chief Data Officer",
"state": "CA"
},
"suggested_fallback_roles": [
{
"n_obs": 63997,
"role": "Executive Director / CEO"
},
{
"n_obs": 902,
"role": "COO"
},
// … 2 more
],
"threshold": 1
}
}
Key management
Mint and revoke API keys on your account page, in the API & Claude Connector section.
- Mint: name a key and create it. The full secret
(
cc_live_…) is shown once, at creation — copy it then; it is never displayed again and never stored in a recoverable form. - Keys are secrets. Treat a key like a password. Anyone holding it can benchmark against your plan (subject to the daily quota). Don't commit keys to source control or paste them into shared documents.
- Revoke: revoking a key takes effect immediately — the very next request with it
returns
401 unauthorized. Rotate by minting a new key and revoking the old. - Connector: the one-click Claude connector uses OAuth, not a key you paste; disconnect it from Claude, or revoke access from your account page, at any time.
Disclaimer
Every benchmark and comparables response carries this text, which you must surface to end users:
CauseComp provides comparability data for informational purposes and does not provide legal or tax advice. Data like this supports — but does not by itself establish — a board's rebuttable presumption of reasonableness under IRC §4958 (intermediate sanctions), which also requires advance approval by an independent board body and contemporaneous documentation. See https://www.causecomp.org.
Questions? Contact us or read the Claude connector page.