Data/ Donor Alignment Index/ 119th Congress ← Back to the index

Data & downloads

Every figure on the site, in two files, with the schema to read them.

The whole index is published as data, for journalists, researchers and anyone who wants to check it. There is no API and no key: these are static files served from the same place as the site. Read the methodology before drawing conclusions from them.

alignment.json ↓ alignment.csv ↓ politicians.json ↓

The files

FileWhat it is
data/alignment.jsonThe canonical output of pipeline/score.py. Never hand-edited. Everything the site shows is read from it.
data/alignment.csvThe same figures flattened by pipeline/export.py: one row per member × industry pair, joined to the roster. Plain CSV, UTF-8 without a byte-order mark, one header row, no comment lines.
politicians.jsonThe roster of 547 officials (House, Senate, President, Vice President, Supreme Court). Joins to the index on bioguide.

alignment.json — schema

A single JSON object, written on one line. Floating-point values are rounded at write time; the rounding is stated per field below. A pair that falls below any coverage floor is absent, never present with a zero.

Top level

FieldTypeMeaning
updated_utcstringWhen the scorer last ran, ISO 8601 UTC, e.g. 2026-09-22T16:13:21Z. Changes on every run, so it is ignored when deciding whether the data changed.
methodstringAlways peer-adjusted donor alignment residual.
notestringA one-paragraph plain-English statement of what the index measures and why there is no overall per-person score.
thresholdsobjectThe coverage floors every published pair has cleared (below).
sourcesobjectMap of upstream feed file name → the base URL (or local directory) it was read from.
industriesobjectMap of industry id → {label, sector}, carried through from the money feed so that labels are never hard-coded. Only industries with at least one published pair appear.
membersobjectMap of bioguide id → member record. Only members with at least one published pair appear; every other official is not measured.

thresholds

FieldTypeMeaning
min_votesintegerFewest informative roll calls in the industry (currently 4).
min_vote_coveragenumberSmallest sum of informativeness weights over those roll calls (currently 1.0).
min_industry_dollarsintegerSmallest direct industry PAC money to the member, US dollars (currently 5000).
min_peersintegerSmallest number of eligible members in the peer group for that industry (currently 12).

members[bioguide]

FieldTypeMeaning
peer_group[string, string, string][chamber, party, tercile], e.g. ["House","R","low"]. Tercile is low, mid or high on DW-NOMINATE first dimension within that chamber and party, or unknown where no score or too few members exist to cut terciles.
strongestobject | null{industry, index} for the member’s highest positive index, or null if they are measured and no industry clears the conjunction (the measured, none found state).
industriesobjectMap of industry id → pair record, for every industry where this member cleared all four floors.

members[bioguide].industries[industry]

FieldTypeMeaning
indexnumber, 3 dpThe Donor Alignment Index: sqrt(money_z × vote_z) where both are positive, otherwise exactly 0.0. Not bounded above; in standard-deviation units.
money_znumber, 3 dpMoney residual: money_share as standard deviations from the peer-group mean for this industry (sample SD). 0.0 if every peer is identical.
vote_znumber, 3 dpVote residual: vote_rate as standard deviations from the same peer group’s mean.
money_sharenumber, 5 dpThis industry’s direct PAC contributions as a share (0–1) of all industry-attributed money the member received.
money_dollarsintegerThose contributions in US dollars. Leadership-PAC, joint-fundraising and independent-expenditure money is excluded.
vote_ratenumber, 4 dpInformativeness-weighted share (0–1) of the industry’s directed roll calls on which the member voted the industry-favoured way.
vote_coveragenumberSum of the informativeness weights behind vote_rate. Higher means the rate rests on more contested votes.
votesintegerNumber of directed roll calls behind vote_rate.
peersintegerSize of the peer population the residuals were taken against: members of the same peer group who also cleared the floors in this industry.

alignment.csv — columns

The CSV is a derived convenience copy. When it and the JSON disagree, the JSON is authoritative. Rows are in a fixed order: measured pairs first, by bioguide then industry_id; then one row per not-measured official. Numbers are written exactly as they appear in the JSON. Empty cells mean no value, never zero. Booleans are true/false.

There are two kinds of row. A pair row exists for every member × industry pair in alignment.json, so the number of rows whose pair_state is not not_measured equals the number of pairs in the JSON. A not-measured row exists, once, for each official in the roster with no record in the JSON; its industry and figure columns are empty. A pair that is simply missing for a member who is measured elsewhere fell below a floor in that industry and has no row.

ColumnSourceMeaning
bioguideJSON keyCongressional Bioguide id. Empty for the President, Vice President and Justices, who have none.
site_idroster idThe site’s own slug for the official; unique, and filled for every row.
namerosterDisplay name.
chamberroster roleHouse, Senate, POTUS, VP or SCOTUS.
staterosterTwo-letter postal code; N/A where not state-based.
partyrosterD, R, I, or N/A.
member_statederivedThe official’s state as shown on the site: measured_alignment (strongest is not null), measured_none (measured, no positive index anywhere) or not_measured.
industry_idJSON keyIndustry id, e.g. oil_gas.
industry_labelindustriesHuman-readable industry name.
industry_sectorindustriesBroad sector, e.g. energy, finance.
pair_statederivedmeasured_alignment where index > 0; measured_none where the pair cleared every floor but index is 0; not_measured on not-measured rows.
is_strongestderivedtrue on the single pair named in the member’s strongest; otherwise false. Empty on not-measured rows.
index … peerspair recordindex, money_z, vote_z, money_share, money_dollars, vote_rate, vote_coverage, votes, peers — exactly as defined in the JSON schema above.
peer_group_keypeer_groupThe three parts joined with |, e.g. House|R|low. Use it to group rows into the populations the residuals were computed against (together with industry_id).
peer_chamber, peer_party, peer_tercilepeer_groupThe same three parts as separate columns.

Spreadsheet users: open the file through an import dialog and declare it UTF-8, or accented names may display incorrectly. Treat bioguide as text.

Reading it responsibly

Upstream feeds

The scorer reads four intermediate feeds published by congressvotetracker, each built from public records. They are published so the inputs can be checked independently of this output.

FeedContentsBuilt from
money_industry.jsonDirect PAC contributions per member per industry; the industry taxonomyFEC bulk downloads (committee master, contributions to candidates)
vote_positions.jsonPer roll call, the vote each industry wanted, composed with motion polaritygovinfo BILLSTATUS subjects and amendments; machine-assigned direction calls with published reasoning
vote_unity.jsonPer roll call, the informativeness weight (largest share of any party that broke ranks)Voteview
member_votes.jsonMember positions, peer keys and DW-NOMINATE first dimensionVoteview

The roster (politicians.json) is drawn from @unitedstates/congress-legislators (CC0).

Update cadence

A scheduled job runs every day at 12:00 UTC, after the upstream morning refresh. It recomputes the index from the live feeds, runs the independent verification in pipeline/verify_score.py, and publishes only if every check passes: a wrong index is worse than a stale one. It commits only when the data has actually changed — a run that differs in nothing but updated_utc commits nothing. So the file’s updated_utc records the last change of substance, and the repository history is a complete, dated record of every version. If an upstream feed is unreachable the previous file is left untouched.

The CSV is regenerated from the JSON by python3 pipeline/export.py and always corresponds to the alignment.json in the same commit. For a fixed snapshot, cite the commit or record updated_utc.

Licence

The code, and the derived data files in this repository, are released under the MIT licence © 2026 AXIA Enterprises: use, copy, modify and redistribute freely, keeping the copyright and permission notice. The underlying records are US government public records (FEC, Congress) and Voteview data; the roster is CC0. Reuse should keep the non-allegation notice below with any figure attributed to a named person.

How to cite

AXIA Enterprises. Donor Alignment Index, 119th Congress [data set].
The Corruption Detector. https://corruptiondetector.org/data.html
File: data/alignment.json, updated_utc <value from the file>. Accessed <date>.

In prose: “According to the Donor Alignment Index published at corruptiondetector.org, [member] is [index] standard deviations above comparable legislators on both [industry] PAC money and [industry]-favoured votes ([dollars], [votes] roll calls, peer group of [peers]). The index is a statistical association, not an allegation of wrongdoing.” Please give the dollars and roll-call count alongside any index you quote.

What the data does not mean

It is a statistical association between contributions received and votes cast, relative to comparable legislators. It is not a finding of corruption, bribery, or any other crime, and no allegation of wrongdoing is made about any person named in these files. Accepting lawful contributions from an industry whose position you already hold is ordinary politics. Causation cannot be read off this data in either direction. A high index is a reason to look more closely at a relationship, and nothing more than that. The PAC-MONEY™ game is satire and contributes nothing to these files.

← Back to the index · Methodology · Notes for AI assistants · The satire game