FEC Campaign Finance - Political Donations & Donors
Pricing
from $2.00 / 1,000 record fetcheds
FEC Campaign Finance - Political Donations & Donors
Search US federal campaign finance data. Find political donations by donor name, candidate, committee, employer, and state. Returns amounts, dates, PDF filing links. Free FEC API, no key required.
Pricing
from $2.00 / 1,000 record fetcheds
Rating
0.0
(0)
Developer
Ryan Clinton
Actor stats
0
Bookmarked
10
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
FEC Campaign Finance — Political Network Intelligence Infrastructure
Deterministic political network intelligence from raw FEC filings — entity-resolved, relationship-mapped, centrality-scored, longitudinally tracked, signal-synthesised, and webhook-ready.
Search FEC campaign finance filings, individual contributions, PAC donations, Super PAC contributions, political donor networks, federal election donations, committee funding, and campaign finance relationships — and get back a deterministic intelligence layer instead of raw rows.
What this is
FEC Campaign Finance is a campaign finance API and political donor network analysis tool that turns raw Federal Election Commission contribution data into entity-resolved, auditable, automation-ready political intelligence.
It is a deterministic political network intelligence infrastructure layer that functions as a campaign finance API, political donor intelligence API, and network-analysis infrastructure layer for developers, analysts, compliance teams, and AI agents — a campaign finance intelligence platform, a political intelligence API, and a donor network analysis infrastructure in a single Apify actor.
This is not another campaign-finance dashboard. It is an operational intelligence layer — built for people who need to know what changed before everyone else does. The actor becomes more valuable every run because political memory compounds longitudinally.
Quick answers
What is FEC Campaign Finance? A campaign finance API and political donor network analysis tool that turns raw Federal Election Commission contribution data into entity-resolved, auditable, automation-ready political intelligence.
What is it best for? Campaign finance intelligence, political donor network analysis, compliance screening, opposition research, lobbying analysis, procurement vendor screening, and agentic monitoring workflows feeding Slack / Jira / Dify / n8n / Snowflake / Neo4j.
How is it different from the raw FEC API? The raw FEC API returns contribution rows. FEC Campaign Finance adds donor canonical IDs, employer normalization, committee classification, relationship mapping (households, executive networks, bundler clusters), network centrality, persistent political memory across runs, deterministic narratives, priority ranking, reproducibility hashes, and automation-ready event records.
Is the intelligence layer deterministic or AI-generated? Deterministic. No LLMs, no probabilistic prediction APIs. Every score recipe is documented in code; every internal lookup-table version is pinned in runManifest; every decision ships with decisionHash / classificationHash / evidenceHash SHA-256 digests so auditors can verify outputs reproduce across runs.
What is the moat? Competitors can backfill data; they cannot backfill historical political memory. The actor's named-KV memory store accumulates cluster lifecycle and donor lifecycle across runs — by run 10 it knows which networks are durable vs transient.
System worldview
Political influence is a memory graph problem, not a donation lookup problem.
Political influence is not a list of donations. It is a persistent network memory problem involving entities, timing, coordination, institutional continuity, and leverage relationships. This actor converts raw FEC filings into a deterministic political memory graph suitable for automation, investigation, network intelligence, and compliance workflows.
Influence emerges from relationships, not rows.
Once political donations are modelled as persistent entities instead of isolated transactions, relationship graphs, trajectories, centrality, and institutional memory become inevitable. Every layer FEC Campaign Finance ships answers a question buyers ask after the previous layer's answer is no longer enough.
Why this is hard to replicate
Competitors can backfill data. They cannot backfill historical political memory.
Most political-data tools help you search donations. FEC Campaign Finance helps you understand durable influence networks. Bloomberg-style political intelligence for donor networks, built as an operational layer instead of a dashboard.
Every alternative that touches FEC data — OpenSecrets, Quorum, FiscalNote, NGP VAN, Aristotle, Bloomberg Government — solves access. None solves the layer above access. The combination FEC Campaign Finance ships is what is hard to rebuild internally:
- Persistent deterministic identity —
donorCanonicalId+entityResolutionConfidencesurvive name / address / employer variants across cycles, runs, and minor filing differences. - Relationship intelligence — households, executive networks, bundler clusters, likely-spousal pairs, donor-network co-donation graphs, and BFS network traversal — all detected from per-record fields with stable cluster IDs that propagate to every contributing record.
- Network centrality — PageRank-style scoring on the donor↔committee↔candidate graph with
politicalReachIndex+crossSectorReach+ stable tier enums. - Longitudinal memory — separate named-KV memory store tracks per-cluster
firstSeenAt/lastSeenAt/runsSeen/persistence(transient → recurring → durable → institutional) and per-donorlifecycleStageacross runs. By run 10 the actor knows which networks are durable; competitors can backfill data but cannot backfill historical memory. - Reproducibility hashes —
decisionHash/classificationHash/evidenceHashSHA-256 digests; same input + same internal rule version always produces the same digest. Procurement / compliance audit unlock. - Event semantics — every narrative + anomaly + emerging-profile + cluster record carries
eventType(namespaced enum) +eventSeverity+eventDedupKeyfor idempotent webhook delivery into Slack / PagerDuty / Jira / Zapier / Make / n8n / agent tool calls.
The progression below is the inevitability arc — once a buyer adopts an FEC pipeline, every step becomes a question they want answered.
The intelligence evolution
| Step | Question | What this actor returns |
|---|---|---|
| 1 | "Show me the donations" | Raw schedule_a contributions + candidates |
| 2 | "Who is this donor really?" | donorCanonicalId + employerCanonical + entityResolutionConfidence |
| 3 | "Who is connected to this donor?" | Households, executive networks, bundler clusters, likely-spousal pairs, donor-network edges |
| 4 | "Which entities are nodes of leverage?" | PageRank centrality + politicalReachIndex + cross-sector reach |
| 5 | "What's emerging? What's cooling?" | Trajectory enum (breakout / accelerating / plateauing / declining) + heuristic forecasts |
| 6 | "Which networks are durable vs transient?" | Cluster lifecycle persistence + donor lifecycleStage across runs |
| 7 | "What matters most this week?" | Priority ranking (P0–P3) collapsed across all signal types |
Raw donation lookups answer step 1. Everything else is the moat.
Design principles
The actor's behaviour is governed by seven hard constraints. They restore trust where most "AI-powered intelligence" products dilute it.
Deterministic systems survive procurement.
- Deterministic over probabilistic — no LLMs, no external prediction APIs. Same input + same internal rule version = same output. Every score recipe is documented in code.
- Explainable over opaque — every decision ships with
evidence[](findings supporting the verdict),counterEvidence[](findings weighing against it), andverdictReasonCodes[](stable enum codes). Black-box scores never leave this actor. - Reproducible over heuristic drift —
runManifestpins every internal lookup-table version (election limits, persona weights, donor-tier thresholds, sibling actors, committee types, anomaly rules, narrative rules, centrality rules, forecast rules, priority rules). Auditors compare manifests across runs. - Structured outputs over prose — every signal carries stable enum tokens (
recordType/decision/riskLevel/donorTier/partisanLean/escalation.level/narrativeType/forecastType/persistence/lifecycleStage/priorityTier/significanceTier). Downstream automation branches on enums, not on natural-language fields. - Event records over notifications — narratives + anomalies + emerging-profiles + clusters + forecasts ship
eventType+eventDedupKeyfor idempotent webhook delivery. Webhooks are downstream; the actor produces events. - Infrastructure over dashboards — outputs are designed for Dify / n8n / Zapier / Make / Slack / Jira / Snowflake / Neo4j ingestion. Dashboards are downstream.
- Network memory over snapshots — institutional patterns accumulate across runs in named-KV stores. By run N+1 the actor knows what it learned in run N.
Epistemic boundaries
The system does not infer hidden political beliefs or probabilistic intent; it computes deterministic relationship and timing structures from public contribution records. The actor infers structural coordination signals, not intent, affiliation, or political motivation. Every "narrative", "forecast", or "synthesis" record is rule-based event composition over existing computed fields — there is no model layer between the FEC API response and the output.
FEC Campaign Finance is designed for audit-sensitive environments where deterministic reproducibility matters more than probabilistic insight generation.
FEC schedule_a + candidates endpoints│▼┌──────────────────────────────────────────────────────────┐│ Entity Resolution Layer ││ donorCanonicalId · employerCanonical · committeeKind │└──────────────────────────────────────────────────────────┘│▼┌──────────────────────────────────────────────────────────┐│ Decision Engine ││ donorTier · partisanLean · isMaxedOut · electionLimit ││ riskScore · materialityScore · decision · escalation ││ evidence · counterEvidence · verdictReasonCodes │└──────────────────────────────────────────────────────────┘│▼┌──────────────────────────────────────────────────────────┐│ Per-Donor Temporal Layer ││ firstSeen · lastSeen · cadence · velocity30d/90d ││ velocityTrend · avgGap · medianGap │└──────────────────────────────────────────────────────────┘│▼┌──────────────────────────────────────────────────────────┐│ Deterministic Anomaly Engine ││ multi-committee-burst · cross-party-donor ││ rapid-sequential-donations · high-frequency-donor ││ employer-cluster · coordinated-timing-cluster ││ max-out-cluster · super-pac-bundling ││ cross-committee-saturation │└──────────────────────────────────────────────────────────┘│┌────────────────────┼────────────────────┐▼ ▼ ▼┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ Cohort Summary │ │ Watchlist Δ │ │ Graph Output ││ topEmployers │ │ new/changed/ │ │ nodes + edges ││ topOccupations │ │ recovered/ │ │ (Neo4j ready) ││ topCommittees │ │ degraded │ │ ││ partisan dist'n │ │ DELTA_RECORDS │ │ donor → committee││ notable findings│ │ │ │ donor → employer ││ decisionReady │ │ │ │ committee → cand │└──────────────────┘ └──────────────────┘ └─────────────────┘
Pure deterministic compute — no LLM calls, no external feeds beyond the FEC API. Every signal is reproducible, every decision is auditable, every classification is versioned in runManifest.
What FEC Campaign Finance is
FEC Campaign Finance is a single Apify actor over the FEC schedule_a + candidates endpoints that returns four orthogonal layers of intelligence on every run:
- Entity Intelligence — canonical donor + employer + committee identity that survives FEC's notoriously dirty input data.
- Network Intelligence — relationships, clusters, centrality, BFS traversal — the moat that raw lookup tools can't replicate.
- Temporal Intelligence — trajectory classification, deterministic forecasting, longitudinal memory, watchlist deltas across runs.
- Operational Intelligence — narratives (deterministic event synthesis), priority ranking, structural significance scoring, automation-grade event records, reproducibility hashes, explainability control.
Pick any of the 13 modes (raw for the v1 contract through network-traversal for investigation work) and the actor returns a typed dataset you can drop into Slack / Jira / Dify / n8n / Snowflake / Neo4j / a CRM without post-processing.
Quickstart
- Open the actor in Apify Console.
- Pick a
mode—rawfor v1-style search;compliance-screenfor KYC;opposition-research/lobbying-intelligencefor analyst dossiers;intel-feedfor Bloomberg-style monitoring;graphfor Neo4j export;network-traversalfor investigation;network-intelligencefor the full v3.1 surface. - Fill the search filters (
contributorName,committeeName,contributorEmployer,contributorState,minAmount,electionYear). - (Optional) Get a free FEC API key at api.open.fec.gov for higher rate limits than the bundled DEMO_KEY (1,000 req/hour).
- Run. Download as JSON / CSV / Excel, or connect via the Apify SDK.
Defaults are sensible — running with no inputs returns Elon Musk's recent contributions in raw mode so the dataset preview shows real data within seconds.
Input parameters
Core search inputs
| Parameter | Type | Default | Description |
|---|---|---|---|
searchMode | select | contributions | "Individual Contributions" (Schedule A) or "Candidates" search. |
contributorName | string | Elon Musk | Donor name to search for. Required for cross-cycle analysis. |
candidateName | string | -- | Candidate name (candidates mode). |
committeeName | string | -- | Filter by receiving committee/PAC (contributions mode). |
contributorEmployer | string | -- | Filter by donor's employer. |
contributorState | string | -- | Two-letter state code (CA, TX, NY...). Works in both modes. |
minAmount | integer | -- | Minimum contribution amount in dollars. |
electionYear | integer | 2024 | Federal election cycle year (even years). |
maxResults | integer | 100 | Maximum number of records to return (1–10,000). |
apiKey | string (secret) | DEMO_KEY | Free FEC API key from api.open.fec.gov for higher rate limits. |
Decision-engine inputs (v2.x)
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | select | raw | Workflow preset — bundles persona + goal + outputProfile + watchlist + decision-engine flags. See mode preset table below. |
persona | select | (mode-derived) | Output consumer — shapes which signals escalate and which are suppressed. See persona table below. |
goal | select | (mode-derived) | Outcome shape — screening / dossier / monitoring / discovery / generic. Tightens or loosens flag thresholds. |
outputProfile | select | (mode-derived) | Field shape per record — minimal / standard / full / llm. |
watchlistName | string | -- | Persistent watchlist key for cross-run delta detection. Required for mode: "monitoring". |
enableCohortSummary | boolean | (mode-derived) | Emit a cohort-summary record at end of run with totals + top employers/occupations/committees + partisan distribution + notable findings. |
enableDecisionEngine | boolean | (mode-derived) | Apply per-donor decision engine (tier / partisan-lean / max-out / risk / escalation). Off in raw mode. |
Intelligence inputs (v2.1 / v2.2)
| Parameter | Type | Default | Description |
|---|---|---|---|
enableInfluenceScoring | boolean | true | Compute per-donor 0–100 influence score. Mirrored to DONOR_INFLUENCE_PROFILES KV. |
enableGeoEnrichment | boolean | true | Add metro / isSwingState / isEliteZip / isFlyover per record. |
enableSectorClassification | boolean | true | Classify employer into a sector enum + emit sectorConfidence (0..1) + sectorMethod (direct-hit / startsWith / heuristic-pattern / no-match). |
enableDataQualityReport | boolean | true | Emit a data-quality record with coverage % per dimension + auditTrustLevel + weak-area callouts + unknown-sector employers + weak donor matches. Mirrored to COVERAGE_SUMMARY KV. |
explainabilityLevel | select | compact | Verbosity of per-record explanation fields. none = stripped (smallest payload), compact = top-2 evidence + reasons, full = entire decision trace. |
enableRelationships | boolean | true | (v3) Detect households / executive networks / bundler clusters / likely-spousal pairs. Emit recordType: "relationship-cluster" + edges. Mirrored to RELATIONSHIPS KV. |
enableCentrality | boolean | true | (v3) PageRank-style centrality on donor↔committee↔candidate graph. Mirrored to CENTRALITY KV (top-50 nodes). |
enableEmergingDetection | boolean | true | (v3) Trajectory classification (emerging/accelerating/plateauing/declining/breakout). Emit recordType: "emerging-profile" records for breakouts. Mirrored to EMERGING_PROFILES KV. |
enableNarratives | boolean | true | (v3) Emit typed recordType: "narrative" records with eventType / eventSeverity / eventDedupKey for downstream automation. Mirrored to NARRATIVES KV. |
enableReproducibilityHashes | boolean | true | (v3) decisionHash / classificationHash / evidenceHash SHA-256 digests per record. Compliance audit unlock. |
enablePriorityRanking | boolean | true | (v3.1) Collapse anomalies + narratives + emerging + clusters into one ranked list with priorityScore 0-100 + tier (P0–P3). Mirrored to PRIORITY_RANKING KV. |
enableEliteClusterScoring | boolean | true | (v3.1) Score each relationship cluster on 7 structural dimensions (density / exclusivity / centrality / cross-sector / timing / committee overlap / seniority). No semantic labels. Mirrored to ELITE_CLUSTERS KV. |
enableForecasting | boolean | true | (v3.1) Deterministic trajectory projections — likely-emerging-mega-donor / likely-future-bundler / cluster-expansion-likely / cooling-trajectory. Mirrored to FORECASTS KV. |
enablePoliticalMemory | boolean | true | (v3.1) Persistent network evolution across runs. Tracks cluster lifecycle + donor lifecycle in a separate named KV store. Requires watchlistName. |
seedDonor | string | -- | donorCanonicalId from a prior run. Required when mode: "network-traversal". |
traversalDepth | integer | 2 | BFS depth from seed donor (1–5). |
traversalEdgeTypes | string[] | (sensible defaults) | Which relationship-edge types to traverse: same-household / likely-spousal / executive-network / donor-network / bundler-cluster / historical-association. |
groupBy | select | -- | Aggregation engine — emit one recordType: "aggregate" per group (employer / committee / occupation / state / metro / sector / candidate / donor / committee-kind). |
crossCycleYears | integer[] | -- | Multi-cycle re-fetch for partisan-shift detection. Requires contributorName. Example: [2020, 2022, 2024]. Each cycle is a separate FEC fetch — costs PPE per record returned. |
Input examples
Find large donors to a specific PAC (v1-style raw search):
{"mode": "raw","committeeName": "America PAC","minAmount": 100000,"electionYear": 2024,"maxResults": 500}
Compliance KYC screening of a named individual:
{"mode": "compliance-screen","contributorName": "Elon Musk","electionYear": 2024,"maxResults": 100}
Industry concentration analysis (lobbying intelligence):
{"mode": "lobbying-intelligence","committeeName": "America PAC","electionYear": 2024,"groupBy": "sector","maxResults": 5000}
Sector aggregation across a candidate's donor base:
{"mode": "committee-watch","committeeName": "Forward Action PAC","electionYear": 2024,"groupBy": "sector","maxResults": 10000}
Graph output for Neo4j / Cytoscape network analysis:
{"mode": "graph","committeeName": "Forward Action PAC","electionYear": 2024,"maxResults": 5000}
Cross-cycle partisan-shift detection:
{"mode": "donor-profile","contributorName": "John Smith","crossCycleYears": [2020, 2022, 2024],"maxResults": 200}
Cross-run monitoring with watchlist:
{"mode": "monitoring","watchlistName": "high-risk-donors-q3-2024","contributorEmployer": "Acme Corp","electionYear": 2024,"maxResults": 500}
Look up presidential candidates:
{"searchMode": "candidates","candidateName": "Trump","electionYear": 2024,"maxResults": 50}
All candidates in a state:
{"searchMode": "candidates","contributorState": "CA","electionYear": 2024,"maxResults": 500}
Input tips
- Use specific donor names for best results. The FEC API matches partial names, so "MUSK" will return all donors with that surname. Use "MUSK, ELON" for more precise results.
- FEC names are uppercase. The FEC stores names in uppercase format (e.g., "BUFFETT, WARREN"). Your search is case-insensitive, but output will be uppercase.
- Filter by employer to find corporate donor patterns. Search "GOOGLE" or "META" to see all contributions from employees of those companies.
- Use minAmount to find large donors. Setting it to 10000 filters out small contributions and focuses on major donors.
- Election years are always even numbers. Federal elections occur every 2 years. Use 2024 for the most recent presidential cycle, 2022 for midterms.
- Get a free API key for production use. The DEMO_KEY works fine for testing but is rate-limited. Register at api.open.fec.gov for a free key with higher quotas.
Output examples
Contribution record (contributions mode)
{"contributorName": "MUSK, ELON","contributorFirstName": "ELON","contributorLastName": "MUSK","amount": 50000000,"aggregateYtd": 50000000,"date": "2024-07-15","committeeName": "AMERICA PAC","committeeId": "C00873893","candidateName": null,"candidateId": null,"candidateOffice": null,"candidateParty": null,"contributorEmployer": "SPACEX","contributorOccupation": "CEO","contributorCity": "AUSTIN","contributorState": "TX","contributorZip": "78701","isIndividual": true,"electionType": "GENERAL","reportYear": 2024,"pdfUrl": "https://docquery.fec.gov/pdf/...","extractedAt": "2025-01-15T12:00:00.000Z"}
Candidate record (candidates mode)
{"candidateId": "P80001571","name": "TRUMP, DONALD J.","party": "REPUBLICAN PARTY","office": "President","state": "FL","district": "","incumbentChallenge": "Incumbent","isActive": true,"electionYears": [2016, 2020, 2024],"firstFileDate": "2015-06-16","hasRaisedFunds": true,"federalFunds": false,"extractedAt": "2025-01-15T12:00:00.000Z"}
Contribution output fields
| Field | Type | Description |
|---|---|---|
contributorName | string | Full donor name as filed (e.g., "MUSK, ELON") |
contributorFirstName | string | Donor's first name |
contributorLastName | string | Donor's last name |
amount | number | Contribution amount in US dollars |
aggregateYtd | number | Total amount the donor has given year-to-date to this committee |
date | string | Date of the contribution (YYYY-MM-DD) |
committeeName | string | Name of the receiving committee or PAC |
committeeId | string | FEC committee ID (e.g., "C00873893") |
candidateName | string|null | Associated candidate name, if linked (null for PAC/party donations) |
candidateId | string|null | FEC candidate ID, if linked |
candidateOffice | string|null | Office sought by the candidate (House, Senate, President) |
candidateParty | string|null | Candidate's party affiliation |
contributorEmployer | string|null | Donor's employer as reported |
contributorOccupation | string|null | Donor's occupation as reported |
contributorCity | string|null | Donor's city |
contributorState | string|null | Donor's state (2-letter code) |
contributorZip | string|null | Donor's ZIP code |
isIndividual | boolean | Whether this is an individual (vs. organization) contribution |
electionType | string|null | Election type: GENERAL, PRIMARY, etc. |
reportYear | number|null | Year of the filing report |
pdfUrl | string|null | Direct URL to the original PDF filing on FEC website |
extractedAt | string | ISO 8601 timestamp of extraction |
Candidate output fields
| Field | Type | Description |
|---|---|---|
candidateId | string | FEC candidate ID (e.g., "P80001571") |
name | string | Candidate name as filed |
party | string | Party affiliation (e.g., "REPUBLICAN PARTY") |
office | string | Office sought: House, Senate, or President (decoded from H/S/P codes) |
state | string | Candidate's state (2-letter code) |
district | string | Congressional district (empty for Senate/President) |
incumbentChallenge | string | Incumbent, Challenger, or Open seat (decoded from I/C/O codes) |
isActive | boolean | Whether the candidate is currently active |
electionYears | number[] | Array of election years the candidate has filed for |
firstFileDate | string|null | Date of the candidate's first filing with FEC |
hasRaisedFunds | boolean | Whether the candidate has raised any funds |
federalFunds | boolean | Whether the candidate has received federal matching funds |
extractedAt | string | ISO 8601 timestamp of extraction |
How this compares to alternatives
| Need | This actor | Raw FEC API | OpenSecrets | Manual workflow |
|---|---|---|---|---|
| Search contributions / candidates | ✅ deterministic decision verdict per record | ✅ raw 60-field JSON | ✅ web UI | ✅ slow |
| Donor canonical ID across name variants | ✅ donorCanonicalId stable across runs | ❌ | ❌ | ❌ |
| Employer normalisation | ✅ corporate suffixes stripped | ❌ raw FEC string | partial | manual |
| Committee classification (Super-PAC / Leadership / Party / Hybrid) | ✅ stable enum + booleans | ⚠ committee_type code only | partial | manual |
| Max-out detection vs federal individual cycle limit | ✅ isMaxedOut + electionLimitStatus | ❌ | ❌ | manual |
| Partisan lean classification | ✅ strong-D / lean-D / mixed / lean-R / strong-R | ❌ | partial | manual |
| Persona-shaped escalation routing | ✅ 8 personas (compliance / journalist / oppo / lobby / procurement / etc.) | ❌ | ❌ | ❌ |
| Anomaly detection (clusters, bundling, cross-party) | ✅ 9 deterministic patterns | ❌ | ❌ | manual |
| Per-donor cadence + velocity | ✅ burst / sustained / periodic + 30d/90d velocity | ❌ | ❌ | manual |
| Cross-run watchlist + delta | ✅ named-KV diff with 5 delta types | ❌ | ❌ | manual |
| Graph output (Neo4j / Cytoscape) | ✅ mode: "graph" returns nodes + edges | ❌ | ❌ | ❌ |
| Cohort summary with top-N + narratives | ✅ employers / occupations / committees / states | ❌ | partial | manual |
| Stable enum tokens for automation | ✅ recordType / decision / riskLevel / donorTier | ❌ | ❌ | ❌ |
| AI-agent / Dify / n8n consumption | ✅ outputProfile: "llm" + actorGraph.next[] + nextActions[] | ❌ | ❌ | ❌ |
The actor is not a Bloomberg / LexisNexis competitor — it is the deterministic political intelligence substrate that sits between FEC's raw feed and the analysts / pipelines / agents downstream of it. No LLM calls, no third-party feeds, no licensing entanglement.
Common workflows
Compliance officer — screen inbound CRM leads for political exposure
{"mode": "compliance-screen","contributorName": "Jane Doe","electionYear": 2024,"maxResults": 50}
Returns: per-record decision enum + escalation.level (immediate-review / standard-review / archive / ignore) + audience tags. Wire into a Dify workflow at signup time; escalation.level === "immediate-review" blocks the signup, decision === "clear" lets it through.
Journalist — investigate donor network at a target employer
{"mode": "donor-profile","contributorEmployer": "Goldman Sachs","minAmount": 1000,"electionYear": 2024,"maxResults": 1000}
Returns: cohort summary with top-employers / top-occupations / partisan distribution + anomaly records (employer-cluster, super-pac-bundling, cross-party-donor) + per-donor evidence/counterEvidence arrays paste-ready for the article.
Opposition researcher — surface cross-party donors and bundling activity
{"mode": "opposition-research","candidateName": "Smith","electionYear": 2024,"maxResults": 5000}
Returns: cross-party-donor anomalies + super-pac-bundling patterns + employer-cluster records, all with severity: "high" and evidence[] arrays usable as story leads.
Lobbying analyst — map industry concentration in a committee's donor base
{"mode": "lobbying-intelligence","committeeName": "America PAC","electionYear": 2024,"maxResults": 10000}
Returns: cohort summary with topEmployers (canonical) + coordinated-timing-cluster + max-out-cluster anomalies. Surfaces which industries are most concentrated in the committee's donor base.
Procurement officer — screen vendors for political exposure conflict-of-interest
{"mode": "compliance-screen","persona": "procurement-officer","contributorEmployer": "Acme Corp","electionYear": 2024,"maxResults": 500}
Returns: per-record escalation.level + escalation.audience: ["procurement", "compliance", "government-contracts"] + flag enum (max-out, cross-party-donor, foreign-address, super-pac-bundling).
Network analyst — extract Neo4j graph of donor → employer → committee → candidate relationships
{"mode": "graph","committeeName": "Forward Action PAC","electionYear": 2024,"maxResults": 5000}
Returns: a single record with recordType: "graph" carrying nodes[] (donors / employers / committees / candidates) + edges[] (donated_to / employed_by / committee_supports) — drop straight into Neo4j, NetworkX, Cytoscape, or any graph viz layer.
Compliance ops — weekly monitoring of a donor watchlist
{"mode": "monitoring","watchlistName": "high-risk-donors-q3-2024","contributorEmployer": "Acme Corp","electionYear": 2024,"maxResults": 1000}
Returns: per-record delta.type (new / changed / unchanged / recovered / degraded) — first run baselines, run 2+ surfaces only what changed. Wire into a Slack alert channel via the DELTA_RECORDS KV mirror.
Modes
Modes bundle persona + goal + output profile + watchlist behaviour. Pick one; override individual fields if needed. mode: "raw" preserves the v1 search contract for back-compatibility.
| Mode | What it's for | Default persona |
|---|---|---|
raw | Original v1 search behaviour. No decisions, no cohort summary. Default. | generic |
due-diligence | KYC-style screening of a named individual. Decision verdict per record + cohort summary. | compliance-officer |
donor-profile | Deep dossier on one donor: tier, partisan lean, employer concentration, max-out status. | journalist |
committee-watch | Profile a candidate/committee's donor base — top employers, top occupations, partisan distribution. | political-strategist |
prospect-research | B2B sales mining — high-tier individual donors, employer-clustered, sortable by amount. | sales-intelligence |
compliance-screen | Strict KYC/PEP — escalate on max-out, foreign address, PAC concentration. SLA-tightened. | compliance-officer |
monitoring | Cross-run change detection. Requires watchlistName. First run baselines; run 2+ surfaces deltas. | compliance-officer |
opposition-research | Surfaces controversial donors, cross-party giving, super-PAC bundling, employer clusters. Anomaly engine on by default. | opposition-research |
lobbying-intelligence | Industry concentration + employer clusters + committee-influence mapping. Heavily weights employer/PAC concentration. | lobbying-intelligence |
graph | Emit nodes (donors / employers / committees / candidates) + edges (donated_to / employed_by / committee_supports) for Neo4j / Cytoscape / NetworkX. | generic |
intel-feed | Bloomberg-terminal style — SKIPS per-contribution push, emits ONLY narratives + anomalies + breakouts + relationship clusters + delta records. Designed for scheduled runs feeding Slack / PagerDuty / Jira. Watchlist on by default. | compliance-officer |
network-intelligence | Full v3 — relationships + centrality + emerging-influence trajectory + narratives + cohort summary + everything. Deepest analysis tier. | political-strategist |
network-traversal | Investigation primitive — BFS from a seedDonor across traversalEdgeTypes to depth traversalDepth. Returns one recordType: "network-traversal" record listing every donor reachable from the seed with their path. Use for "show me everyone connected to this donor" workflows. | opposition-research |
Pillar 1 — Entity Intelligence
Canonical donor + employer + committee identity that survives FEC's notoriously dirty input data. The foundation every other layer joins on.
Raw filings become operational intelligence only after identity resolution.
Donor canonical identity
When enableDecisionEngine: true (default for every mode except raw), every contribution carries:
| Field | Description |
|---|---|
donorCanonicalId | Stable synthetic identity (donor_<12-char hash>) built from normalised name + state + ZIP-5 + city + canonical employer. Same donor across cycles, runs, and minor name variants resolves to the same ID. |
entityResolutionConfidence.score | 0..1 — share of donor identity fields populated. 5/5 fields = 1.0. |
entityResolutionConfidence.level | high (≥0.8) / medium (≥0.6) / low (≥0.4) / very-low. Stable enum. |
entityResolutionConfidence.fieldsContributed[] / fieldsMissing[] | Which fields contributed to the canonical ID, which are missing. |
Name normalisation handles "LAST, FIRST" → "FIRST LAST", strips honorifics + suffixes, collapses whitespace, uppercases. Address normalisation strips ZIP+4 to ZIP-5, uppercases state, normalises city.
Employer normalisation + sector classification
When enableSectorClassification: true (default):
| Field | Description |
|---|---|
employerCanonical | Normalised employer string — corporate suffixes (LLC / INC / CORP / LTD / GROUP / HOLDINGS / etc.) stripped, ampersands → "AND", uppercase, deduped spaces. Does NOT map to canonical entities ("Alphabet Inc.") — that's ryanclinton/company-deep-research's job. |
employerStatus | Stable enum: retired / unemployed / self-employed / homemaker / requested / employed / unknown. Filters out non-itemizable / pseudo-employer noise. |
sector | 36-value enum derived from a curated lookup of ~250 top FEC employers + heuristic regex fallback (e.g. … UNIVERSITY → education, … BANK → commercial-banking). |
sectorConfidence | 0..1 — 1.0 for direct-hit, 0.85 for startsWith match, 0.5–0.65 for heuristic patterns, 0 for no-match. |
sectorMethod | direct-hit / startsWith / heuristic-pattern / no-match — branch on this in audits. |
Committee classification
Every contribution carries the committee classification derived from FEC committee_type codes:
| Field | Description |
|---|---|
committeeKind | Stable enum: authorized-candidate / leadership-pac / super-pac / hybrid-pac / party-national / party-state-local / separate-segregated / non-qualified-pac / unknown. |
committeeKindLabel | Human-readable label. |
isSuperPac | True for FEC committee_type: "O" — accepts unlimited individual contributions. |
isLeadershipPac | True from FEC designation OR name pattern. |
isPartyCommittee / isCandidateCommittee / isHybridPac / isPac | Convenience booleans for direct equality matching in Dify / Zapier rules. |
Filing intelligence
Fields present in the FEC response that v1 didn't surface:
| Field | Description |
|---|---|
amendmentIndicator | FEC amendment code: N (new) / A (amendment) / T (termination). |
isAmended | Convenience boolean — true when amendmentIndicator is A or T. |
memoText | FEC memo text — often documents joint-fundraising context, attribution rules, or earmark notes. |
memoCode | FEC memo code (X = no monetary effect — important for compliance sums). |
reportType | FEC report type code (M3 / Q3 / 12P / 30G / etc.). |
Geographic enrichment
When enableGeoEnrichment: true (default):
| Field | Description |
|---|---|
metro | MSA name from ZIP3 lookup (~150 curated metros covering top US donor density). Null when ZIP not in curated set. |
isSwingState | True when donor state is in PA / MI / WI / AZ / GA / NV / NC. |
isEliteZip | True for top-percentile mean-AGI ZIPs (curated from IRS SOI consensus). |
isFlyover | True when ZIP is not in any of the top-N curated metro areas. |
Decision-engine fields per record
When mode is anything other than raw, every contribution record gets:
| Field | Type | Description |
|---|---|---|
decision | enum | clear / noted / flag / escalate. Stable. |
decisionPosture | enum | auto-approve / manual-review / block. Stable. |
decisionReason | string | Single-sentence "decision · risk · materiality · top-reason" paste-ready justification. |
riskLevel | enum | critical / high / medium / low / none. Stable. |
riskScore | 0–100 | Numeric risk. |
materialityScore | 0–100 | Persona-weighted materiality. |
donorTier | enum | mega-donor (≥$50k cycle) / major ($10–50k) / large ($3.3–10k) / mid ($500–3.3k) / small (<$500). |
isMaxedOut | boolean | True when YTD aggregate hits the federal individual cycle limit. FEC indexes the limit each cycle: $6,600 for 2024 ($3,300/election × 2), $7,000 for 2026 ($3,500/election × 2). The actor's electionLimit field surfaces the exact cycle limit used. |
electionLimitStatus | enum | under / approaching (≥90%) / at-limit / over-limit / unknown. |
partisanLean | enum | strong-D / lean-D / mixed / lean-R / strong-R / none. |
isOutOfState / isForeignAddress | boolean | Donor state ≠ candidate state / donor address fails US state validation. |
flags[] | string[] | Stable enum tokens (max-out, foreign-address, mega-donor, etc.). |
evidence[] / counterEvidence[] | string[] | Findings supporting / weighing against the verdict — classifier with receipts. |
verdictReasonCodes[] | string[] | Stable enum codes (VERDICT_MAX_OUT / VERDICT_FOREIGN_ADDRESS / etc.) for downstream branching. |
decisionTrace[] | string[] | Flat enum codes for downstream branching. |
whyThisMatters | string | Plain-English ≤200-char explanation. |
summary | string | Paste-ready ≤280-char one-liner. |
shortReason | string | One-phrase compressed reason for UI tiles / Slack messages. |
escalation | object | level (immediate-review / standard-review / archive / ignore) + sla + audience[] + reason + ignoreRecommendation. |
nextActions[] | object[] | Ranked sibling-actor calls with input hints (drives suite usage). |
actorGraph | object | Suite navigation: previous / current / next[]. |
pipelineState / executionReadiness | object | What's been done / what's blocking automation. |
Pillar 2 — Network Intelligence
The moat. Five new entity types, seven edge types, PageRank centrality, BFS traversal — relationship inference that raw lookup tools can't replicate.
Networks matter more than transactions.
Most campaign-finance tools stop at donation search. FEC Campaign Finance adds relationship mapping, network traversal, trajectory analysis, and persistent political memory. Designed for opposition research, compliance investigations, lobbying analysis, procurement review, and political network mapping. This is the political graph intelligence layer raw FEC search results can't produce.
Relationship intelligence layer
When enableRelationships: true (default), the actor detects:
| Relationship | Trigger | Output |
|---|---|---|
| Same-household | 2+ donors at same ZIP5 + same last name | householdCanonicalId per record + recordType: "relationship-cluster" (type: household) |
| Likely-spousal | Same household + distinct first names | same-household edge upgraded to likely-spousal (strength 0.85) |
| Executive network | 2+ donors at same employer + senior title (CEO/VP/Founder/Partner/Director/etc.) + ≥$1k aggregate | executiveNetworkId per record + cluster record |
| Bundler cluster | 5+ distinct donors at same employer in 14-day window | bundlerClusterId per record + cluster record + eventType: POLITICAL.BUNDLER_CLUSTER_DETECTED |
| Donor network | Two donors who co-donated to ≥3 of the same committees | donor-network edge in RELATIONSHIPS KV |
Every cluster record carries memberDonorIds[], memberCount, totalContributedUsd, timingTightness (0..1; 1.0 = ≤7-day burst), committeeDiversification, seniorityHits, and a paste-ready headline. Edges live in the RELATIONSHIPS KV with stable type enum (same-household / likely-spousal / executive-network / donor-network / bundler-cluster / historical-association) + relationshipStrength (0..1) + sharedSignals[].
Network centrality
When enableCentrality: true (default), PageRank-style centrality runs on the donor↔committee↔candidate graph (30 iterations, damping 0.85, edge-weighted by USD). Top-50 nodes mirrored to CENTRALITY KV:
| Field | Description |
|---|---|
pagerankScore | 0..1 normalised |
pagerankTier | top-1pct / top-5pct / top-10pct / top-25pct / rest |
degree / weightedDegree | Raw + USD-weighted edge sums |
crossSectorReach | Count of distinct sectors touched |
politicalReachIndex | 0–100 composite (pagerank × 50 + cross-sector × 4 + log10(weighted-degree) × 4) |
explanation | Plain-English reach summary |
Investigation primitive: BFS traversal
mode: "network-traversal" with seedDonor, traversalDepth (1–5), and traversalEdgeTypes[]:
{"mode": "network-traversal","seedDonor": "donor_a3c7f1d4e2b9","traversalDepth": 2,"traversalEdgeTypes": ["same-household", "executive-network", "donor-network", "bundler-cluster"]}
Returns one recordType: "network-traversal" record listing every donor reachable from the seed within depth, with their path back to the seed (which edge types were traversed) and per-node aggregates. Drop into Neo4j or Cytoscape; or use directly as the input for a follow-up enrichment pipeline. Mirrored to NETWORK_TRAVERSAL KV.
Elite-cluster structural significance scoring
When enableEliteClusterScoring: true (default), every relationship cluster gets a structural significance score with recordType: "elite-cluster-significance". No semantic labels ("Silicon Valley libertarian cluster") — pure structural signals:
| Component | Weight | What it measures |
|---|---|---|
| density | 20% | Cluster's share of cohort dollars |
| exclusivity | 10% | Smaller, denser clusters score higher (3–12 members optimal) |
| centrality | 20% | Average pagerank tier of members |
| crossSectorReach | 10% | Distinct sectors touched |
| timingSynchrony | 15% | Direct from cluster.timingTightness |
| committeeOverlap | 10% | Concentrated targets = high overlap signal |
| seniorityDensity | 15% | Share of senior-titled members |
significanceTier: institutional (≥80) / high (≥60) / notable (≥40) / background. Mirrored to ELITE_CLUSTERS KV. Lets consumers branch WHERE significanceTier IN ('institutional', 'high') to surface only structurally-meaningful networks.
Graph output mode (Neo4j-ready)
mode: "graph" emits a single record with recordType: "graph" carrying nodes + edges. Drops directly into Neo4j, NetworkX, Cytoscape, Cosmograph — no transformation needed.
| Node type | Properties |
|---|---|
donor | donorCanonicalId, isIndividual, donorTier, isMaxedOut, state, city, occupation, cycleAggregateYtd |
employer | canonical employer name |
committee | committeeId, committeeKind, isSuperPac, isLeadershipPac, isPartyCommittee |
candidate | candidateId, party, office, state |
| Edge type | Properties |
|---|---|
donated_to | count, totalAmount, firstDate, lastDate |
employed_by | count, totalDonated |
committee_supports | count |
Pillar 3 — Temporal Intelligence
The longitudinal layer. Per-donor cadence + cross-cycle behavioural analysis + trajectory + heuristic forecasting + institutional memory across runs. Competitors can backfill data; they cannot backfill historical memory.
Influence is temporal before it is financial. Political memory compounds across cycles.
Per-donor temporal profile
Mirrored to DONOR_TEMPORAL_PROFILES KV when the cohort has multiple donations per donor:
| Field | Description |
|---|---|
cadence | one-time / periodic / burst / campaign-window / sustained / unknown |
firstSeen / lastSeen | Earliest / latest contribution date in the cohort window |
spanDays | Days between first and last seen |
velocity30d / velocity90d | Sum of contributions in the last 30 / 90 days of the cohort window |
velocityTrend | accelerating / steady / decelerating / unknown |
avgGapDays / medianGapDays | Gap statistics between consecutive donations |
Cross-cycle behavioural analysis
Pass crossCycleYears: [2020, 2022, 2024] along with a contributorName and the actor re-fetches each cycle, joins on donorCanonicalId, and emits recordType: "cross-cycle-profile" records:
| Field | Description |
|---|---|
cyclesObserved / cyclesObservedCount | Election years the donor appeared in |
cycles[year] | Per-cycle snapshot (lean, dShare, rShare, total, primary recipient) |
overallLean | Cross-cycle weighted partisan lean |
partisanShiftDetected | Boolean — true when lean changed across cycles |
shiftSeverity | none / minor / moderate / major |
shiftDirection | D-to-R / R-to-D / partisan-to-mixed / mixed-to-partisan |
shiftConfidence | high (≥3 cycles + ≥5 contributions) / medium / low |
shiftEvidence[] | Per-cycle evidence strings paste-ready for stories / reports |
longevity | one-cycle / two-cycles / durable (3) / long-term (≥4) |
Mirrored to CROSS_CYCLE_PROFILES KV. Each additional cycle costs PPE per record returned.
Trajectory + emerging-influence detection
When enableEmergingDetection: true (default), every donor with multi-period data gets a trajectory classification:
| Trajectory | Trigger |
|---|---|
breakout | Prior aggregate <$1k AND now ≥$10k AND velocity ≥3× |
accelerating | Velocity ≥1.5× recent vs prior + network expansion ≥1.3× |
plateauing | Velocity 0.8–1.2×, ≥3 contributions |
declining | Velocity <0.7× of prior pace |
emerging | First-time observation with ≥$5k aggregate |
unknown | Insufficient temporal signal |
emergingInfluenceScore 0–100 composite + velocityAcceleration + networkExpansionRate + committeeDiversificationRate + plain-English explanation[]. Breakout / accelerating donors emit dedicated recordType: "emerging-profile" records with eventType: POLITICAL.DONOR_BREAKOUT for downstream automation. Mirrored to EMERGING_PROFILES KV.
Heuristic forecasting
When enableForecasting: true (default), the actor emits deterministic recordType: "forecast" records — heuristic projections, NOT ML predictions:
| Forecast Type | Trigger |
|---|---|
likely-emerging-mega-donor | Breakout trajectory + emergingInfluenceScore ≥70 + tier in {major, large} |
likely-future-bundler | Executive-network cluster + ≥3 members + seniorityShare ≥0.5 + timingTightness ≥0.4 |
cluster-expansion-likely | Bundler-cluster + committeeDiversification ≥0.5 |
cooling-trajectory | Declining trajectory + velocity ≤0.5 + tier in {major, mega-donor} |
Every forecast record carries explicit methodology, horizon (next-cycle / next-30-days / next-90-days / open-ended), confidence, and a standard caveats[] array reminding consumers these are heuristic projections — same input + same internal rule version = same forecast (deterministic). Mirrored to FORECASTS KV.
Watchlist + cross-run delta
Set watchlistName (or pick mode: "monitoring") to persist donor snapshots in a named KV store. First run baselines; run 2+ surfaces a delta block per record:
delta.type:new/changed/unchanged/recovered/degradedrecovered: prior decision wasflag/escalate, current isclear/noted(impact: high)degraded: prior decision wasclear/noted, current isflag/escalate(impact: high)delta.fieldsChanged[]— which fields shifteddelta.previous— prior snapshot for comparison
A DELTA_RECORDS KV key carries only the records whose delta.type !== 'unchanged' — drop-in for Slack alerts.
First-run note: different watchlistName values keep separate state. The first run after a watchlist setup will mark every record as delta.type: "new" (no prior snapshot exists yet) — correct first-run behaviour, not a bug.
Political memory graph (institutional memory)
When enablePoliticalMemory: true AND watchlistName is set, the actor maintains a separate named KV store (fec-campaign-finance-memory-<watchlistName>) tracking cluster + donor lifecycle across runs.
Per-cluster memory (recordType: "memory-cluster-lifecycle"):
firstSeenAt/lastSeenAt/runsSeenhistoricalMemberDonorIds— union of memberships across all runstotalContributedUsdMax— peak across runspersistence:transient(1 run) /recurring(≥2) /durable(≥5) /institutional(≥10) — stable enum
Per-donor lifecycle (mirrored to DONOR_LIFECYCLE KV):
firstSeenAt/lastSeenAt/runsSeencumulativeAmount/cumulativeContributions(across runs, not just current cohort)distinctCommitteesEverSeen/distinctEmployersEverSeenmemberOfClusterIds[]— union of cluster memberships everlifecycleStage:new/returning(≥2) /sustained(≥5) /durable(≥10)
By run 10, FEC Campaign Finance knows which networks are transient vs durable. Recurring/durable clusters fire eventType: POLITICAL.RECURRING_CLUSTER or POLITICAL.INSTITUTIONAL_CLUSTER_DETECTED for downstream automation. This is the proprietary moat — competitors can backfill data but cannot backfill historical memory.
Once donor activity is modelled longitudinally instead of transactionally, political influence becomes a memory graph rather than a filing archive.
This is the campaign finance monitoring infrastructure layer most political-data tools never reach.
Pillar 4 — Operational Intelligence
The automation-grade output layer. Anomalies, signal synthesis, priority ranking, cohort summaries, aggregation, event records, reproducibility hashes — designed for direct ingestion into Slack / Jira / Dify / n8n / Snowflake without post-processing.
Memory compounds faster than data.
Designed for agentic monitoring workflows where AI systems continuously watch donor networks, emerging influence clusters, and political-finance anomalies over time. FEC Campaign Finance is the campaign finance API layer agentic stacks reach for when raw FEC search results aren't structured enough for autonomous decision loops.
Anomaly engine
When enableDecisionEngine: true, the actor runs a pure-rules anomaly pass over the cohort and emits one recordType: "anomaly" record per pattern detected:
| Pattern | Trigger | Severity |
|---|---|---|
multi-committee-burst | Single donor → 5+ distinct committees within 30 days | high |
super-pac-bundling | Single donor → 3+ super-PACs within 30 days | high |
cross-party-donor | Donor gave to BOTH Democratic and Republican candidates this cycle | medium |
rapid-sequential-donations | 3+ donations in <72 hours from same donor | medium |
high-frequency-donor | >20 contributions from same donor in cohort window | medium |
cross-committee-saturation | Donor → super-PAC + party-national + leadership-PAC simultaneously | medium |
employer-cluster | 3+ employees of same employer → same committee | high |
coordinated-timing-cluster | 3+ employees of same employer donating within 7-day window | medium |
max-out-cluster | 3+ maxed-out donors at same employer | high |
Every anomaly record carries evidence[] strings, affectedDonorIds[] (linked via donorCanonicalId), affectedCommitteeIds[], affectedEmployers[], and a paste-ready headline + detail. Mirrored to ANOMALIES KV.
Signal synthesis engine (deterministic event synthesis — NOT LLM)
When enableNarratives: true, the actor emits typed recordType: "narrative" records derived from cohort + relationship + anomaly + emerging outputs. Pure deterministic synthesis from existing computed signals — no LLM, no external feeds, no probabilistic generation. The recordType is narrative (stable wire contract), but the implementation is rule-based event synthesis.
| Field | Description |
|---|---|
narrativeType | Stable enum: employer-coordination / executive-network-activation / household-cluster / super-pac-bundling-narrative / max-out-cluster / cross-party-pattern / breakout-emergence / committee-saturation / sector-concentration / metro-concentration / partisan-flip-cluster. |
headline | Paste-ready exec-line ("Senior executives at Goldman Sachs activated as a coordinated political network, contributing $2.1M across 14 executives.") |
detail | Long-form context |
confidence | high / medium / low |
drivers[] | Plain-English drivers |
evidence[] | Specific data points supporting the synthesis |
eventType / eventSeverity / eventDedupKey | Automation-grade routing primitives |
affectedDonorIds[] / affectedEmployers[] / affectedCommitteeIds[] | Linkage back to source records |
metricUsd | Anchor dollar metric |
Mirrored to NARRATIVES KV. Journalists and lobbyists paste these directly into stories / briefs.
Priority ranking
When enablePriorityRanking: true (default), the actor collapses anomalies + narratives + emerging-profile + cluster records into one ranked list with recordType: "priority-ranking":
| Field | Description |
|---|---|
priorityScore | 0–100 composite (base score per record-type × severity weight × confidence boost × dollar boost) |
priorityTier | P0-investigate-now (≥75) / P1-this-week (≥55) / P2-monitor (≥35) / P3-archive. Stable enum. |
sourceRecordType | Which kind of record this priority entry was derived from. |
sourceId | Stable ID linking back to the source. |
priorityReasons[] | Plain-English drivers — paste-ready into a Slack triage thread. |
Every record gets a rank (1 = highest). Mirrored to PRIORITY_RANKING KV. Replaces "drowning in 14 anomaly records" with "here are the top 5, ranked, with reasons."
Cohort summary
When the run produces ≥1 contribution record AND the mode enables it (anything other than raw), the actor pushes one extra record at the end with recordType: "cohort-summary":
headline+oneLine+diagnosis— paste-ready exec linestopEmployers/topOccupations/topCommittees/topStates— top-5 by amount with count + sharetopDonors— top-10 by cycle aggregatepartisanDistributionwithleanLabeldonorTierDistribution/decisionDistribution/flagDistributionmaxOutCount/foreignAddressCount/outOfStateCountcohortRiskLevel/cohortDecision/decisionReadiness/confidenceLevelnotableFindings[]— automatic cohort-level callouts
Mirrored to COHORT_SUMMARY KV.
Aggregation engine (groupBy)
Pass groupBy: "employer" (or committee / occupation / state / metro / sector / candidate / donor / committee-kind) to emit one recordType: "aggregate" record per group:
| Field | Description |
|---|---|
groupKey / groupLabel | Stable key + human-readable label |
contributionCount / uniqueDonors / uniqueCommittees | Cardinality |
totalAmount / avgAmount / medianAmount | Amount stats |
maxOutCount / foreignAddressCount | Risk indicators |
decisionDistribution / partisanDistribution / partisanLean | Cohort-level decision/partisan rollup |
flags[] | Top-5 flags by frequency |
sharePercent | Group's share of cohort total |
rank | Position in the cohort by total amount |
Mirrored to AGGREGATES KV. Different from cohort-summary's top-5 lists — this returns the FULL grouped breakdown for BI dashboards.
Influence scoring
When enableInfluenceScoring: true (default), every donor gets an influence score. Mirrored to DONOR_INFLUENCE_PROFILES KV:
| Field | Description |
|---|---|
influenceScore | 0–100 composite |
influenceTier | mega-influence (≥80) / high-influence (≥60) / mid-influence (≥40) / low-influence (≥20) / minimal |
components | amount 30% / spread 20% / committeeImportance 20% / candidateTargeting 15% / velocity 10% / maxOut 5% (documented weight pack) |
weights | Exposed for audit |
explanation[] | Plain-English drivers paste-ready into reports |
Event records (automation-grade)
Every narrative + emerging-profile + bundler-cluster + breakout + memory-cluster-lifecycle record ships with:
{"eventType": "POLITICAL.BUNDLER_CLUSTER_DETECTED","eventSeverity": "critical","eventDedupKey": "bundler_a3c7f1d4e2"}
Stable namespaced enums (POLITICAL.BUNDLER_CLUSTER_DETECTED / POLITICAL.EXEC_NETWORK_ACTIVATED / POLITICAL.HOUSEHOLD_CLUSTER / POLITICAL.SUPER_PAC_BUNDLING / POLITICAL.CROSS_PARTY_DONOR / POLITICAL.MAX_OUT_CLUSTER / POLITICAL.COMMITTEE_SATURATION / POLITICAL.DONOR_BREAKOUT / POLITICAL.DONOR_ACCELERATING / POLITICAL.RECURRING_CLUSTER / POLITICAL.INSTITUTIONAL_CLUSTER_DETECTED / POLITICAL.FORECAST_*). Webhook consumers branch on eventType, dedupe on eventDedupKey for idempotent delivery, route by eventSeverity (critical / high / medium / low).
Reproducibility hashes
When enableReproducibilityHashes: true (default), every contribution carries:
| Hash | Inputs |
|---|---|
decisionHash | (schemaVersion, decision, riskLevel, materialityScore, flags, verdictReasonCodes) — dec_<16-char> |
classificationHash | (donorTier, partisanLean, committeeKind, sector, employerStatus) — cls_<16-char> |
evidenceHash | (evidence[], counterEvidence[]) — evd_<16-char> |
Same input + same internal rule version always produces the same digest. Compliance auditors verify model behaviour reproduces deterministically across runs without re-deriving outputs.
Output profile + explainability level
| Profile | Includes |
|---|---|
minimal | recordType, decision, riskLevel, donorTier, isMaxedOut, partisanLean, summary + key identity |
standard | minimal + raw FEC fields + decision details + escalation + nextActions (default for most modes) |
full | everything internal |
llm | minimal + whyThisMatters + reasons + flags + confidence + actorGraph + nextActions |
explainabilityLevel controls per-record verbosity:
| Level | What ships |
|---|---|
none | Strips evidence / counterEvidence / reasons / whyThisMatters / materialityComponents / decisionTrace / verdictReasonCodes. Smallest payload. |
compact (default) | Top-2 evidence + top-2 reasons + summary / whyThisMatters. |
full | Entire decision trace including counter-evidence, full materiality components, suppressed signals, all reasons. |
Run manifest (reproducibility)
Every run writes a MANIFEST KV record pinning the actor version, mode, persona, goal, output profile, watchlist name, and ten internal lookup-table versions: electionLimitsVersion / personaWeightsVersion / donorTierThresholdsVersion / siblingActorsVersion / committeeTypesVersion / anomalyRulesVersion / relationshipRulesVersion / narrativeRulesVersion / centralityRulesVersion / forecastRulesVersion / priorityRulesVersion. Compliance / audit consumers compare manifests across runs to spot internal-rule drift.
Data quality + coverage (audit-trust gate)
When enableDataQualityReport: true (default), every run emits one recordType: "data-quality" record carrying:
coverage.donorCanonicalIdResolutionPct/employerPresentPct/sectorMappedPct/sectorDirectHitPct/metroMappedPct/statePresentPct/zipPresentPct/candidatePartyPresentPct/amendmentRecordPct/memoTextPresentPctweakAreas[]— plain-English coverage gaps ready to paste into a Slack alertunresolvedEmployers[]— top-5 records where employer was missingunknownSectorEmployers[]— top-10 employers whose sector classification returnedno-match(candidates for adding to the curated lookup)weakDonorMatches[]— top-10 donors withentityResolutionConfidence.score < 0.5(high false-positive risk on cross-cycle joins)auditTrustLevel:high/medium/low— production-automation gateauditTrustReason— paste-ready justification for the trust level
Mirrored to COVERAGE_SUMMARY KV. Compliance / audit consumers branch WHERE auditTrustLevel = 'high' before flipping a workflow to auto-execute.
Persona
Persona shapes which signals escalate and which are suppressed. Set mode first; override persona only if you want a different shaping.
| Persona | What it surfaces | Suppresses | Default audience tags |
|---|---|---|---|
compliance-officer | max-outs, foreign addresses, PAC concentration, aggregate-limit-exceeded. SLA tightened. | partisan-lean | compliance / kyc / aml |
journalist | large amounts, partisan flips, employer clusters. | — | newsroom / oppo-research |
sales-intelligence | mega/major-donor tier, employer concentration, large amounts. | foreign-address, partisan-lean | sales / sdr / go-to-market |
political-strategist | partisan intensity, committee concentration, cross-cycle shift. | — | campaign / opposition-research |
opposition-research | cross-party donors, super-PAC bundling, max-out behaviour, employer clusters. | — | campaign / opposition-research / newsroom |
lobbying-intelligence | employer concentration, PAC concentration, cross-committee saturation. | partisan-lean | policy / lobbying / regulatory |
procurement-officer | vendor max-outs, foreign addresses, super-PAC bundling — for conflict-of-interest review. | — | procurement / compliance / government-contracts |
generic | even weights, no shaping. | — | general |
Stable enum tokens
These enums are part of the public contract — values may be added in minor versions, never renamed or repurposed.
recordType:contribution/candidate/cohort-summary/aggregate/relationship-cluster/anomaly/narrative/emerging-profile/cross-cycle-profile/forecast/priority-ranking/elite-cluster-significance/memory-cluster-lifecycle/network-traversal/graph/data-quality/no-results/errordecision:clear/noted/flag/escalatedecisionPosture:auto-approve/manual-review/blockriskLevel:critical/high/medium/low/nonedonorTier:mega-donor/major/large/mid/smallpartisanLean:strong-D/lean-D/mixed/lean-R/strong-R/noneelectionLimitStatus:under/approaching/at-limit/over-limit/unknownescalation.level:immediate-review/standard-review/archive/ignorecommitteeKind:authorized-candidate/leadership-pac/super-pac/hybrid-pac/party-national/party-state-local/separate-segregated/non-qualified-pac/unknownsector: 36-value enum (see Pillar 1)employerStatus:retired/unemployed/self-employed/homemaker/requested/employed/unknownnarrativeType: see Pillar 4forecastType:likely-emerging-mega-donor/likely-future-bundler/likely-network-activation/probable-committee-migration/cooling-trajectory/cluster-expansion-likelytrajectory:breakout/accelerating/plateauing/declining/emerging/unknownpersistence:transient/recurring/durable/institutionallifecycleStage:new/returning/sustained/durablepriorityTier:P0-investigate-now/P1-this-week/P2-monitor/P3-archivesignificanceTier:institutional/high/notable/backgroundpagerankTier:top-1pct/top-5pct/top-10pct/top-25pct/restdelta.type:new/changed/unchanged/recovered/degradedeventType:POLITICAL.*namespaced (see Pillar 4)errorType/failureType:rate-limited/auth-failed/timeout/server-error/network/unknown
Honest scope-fence
This actor does NOT:
- Pre-label elite-network clusters with subjective tags ("Silicon Valley libertarian cluster") — that requires political-judgment external data we don't have. We emit the deterministic cluster + sector mix + centrality scores; consumers label.
- Fire webhooks itself — we emit event records with
eventType/eventDedupKey; downstream automation (Zapier / Make / n8n / direct webhook handler) does the firing. - Track real-time legislative outcomes — that's
quorum.us/fiscalnote.comterritory. - Replace campaign operations — we are NOT competing with
ngpvan.com/aristotle.com. The positioning is intelligence coprocessor, not campaign OS. - Use ML / LLMs / probabilistic generation. Every "narrative", "forecast", "synthesis" record is deterministic event composition from existing computed signals.
Suite navigation — sibling actors
When the decision engine is on, every record gets an actorGraph.next[] array pointing at sibling Apify actors that can extend the dossier:
ryanclinton/person-enrichment-lookup— enrich the donor with a professional profile (LinkedIn, work history).ryanclinton/company-deep-research— profile the donor's employer.ryanclinton/sec-edgar-filing-analyzer— pull SEC filings when the employer is a public company.ryanclinton/nonprofit-explorer— cross-reference 501(c)(4) dark-money donations on the same name.
When NOT to use this actor
- For state-level campaign finance — FEC only covers federal contributions. Use a state-specific source.
- For corporate or independent-expenditure committee aggregate spending — Schedule A is itemized individual contributions; use Schedule E or committee summaries instead.
- For real-time same-day data — FEC filing cadence is monthly/quarterly; expect 2-4 week lag on new records.
Use in Dify
Drop this actor into Dify workflows via the Apify plugin's Run Actor node. Each contribution returns scored, classified, and verdicted as structured JSON — clear / noted / flag / escalate plus the donorTier, riskLevel, partisanLean, and escalation.level enums your downstream node branches on. A raw FEC API call returns 60-field JSON arrays you have to parse; this returns decisions.
- Actor ID:
ryanclinton/fec-campaign-finance - Sample input (KYC screening of a named individual):
{"mode": "compliance-screen","contributorName": "Elon Musk","electionYear": 2024,"maxResults": 100}
- Sample input (B2B prospect research — find high-tier donors at a target employer):
{"mode": "prospect-research","contributorEmployer": "Goldman Sachs","minAmount": 5000,"electionYear": 2024,"maxResults": 500}
Dify if/else branching example
A Dify if/else node consumes the actor's stable enum tokens directly — no LLM rewriting, no JSONata expressions, no field parsing.
IF decision == "escalate" AND escalation.level == "immediate-review"→ branch: route to compliance Slack channel + create Jira ticketELSE IF decision == "flag" AND donorTier IN ["mega-donor", "major"]→ branch: enrich with ryanclinton/person-enrichment-lookupELSE IF decision == "noted" AND isMaxedOut == true→ branch: add to watchlist for next runELSE→ branch: archive
Boolean gates that work as direct equality matches in Dify:
isMaxedOut— donor hit the federal individual cycle limitisForeignAddress— donor address fails US-state validation (compliance flag)isOutOfState— donor state ≠ candidate stateescalation.ignoreRecommendation— materiality below persona threshold (filter out)executionReadiness.readyForReview— record is reviewable (no blockers)pipelineState.verifiedDonor— donor has employer + occupation populated
Suite navigation in Dify
Every record carries a nextActions[] array with sibling-actor IDs Dify can chain to in a multi-step flow:
Step 1: ryanclinton/fec-campaign-finance (this actor)Step 2: For each record where decision IN ["flag", "escalate"]:- Call ryanclinton/person-enrichment-lookup with nextActions[0].inputHint- Call ryanclinton/company-deep-research with nextActions[1].inputHintStep 3: Merge results into a Dossier object
The actorGraph.next[] array on every record is the wire-format Dify multi-step iteration consumes verbatim — no field renaming, no LLM rewriting.
Mode presets that pair with Dify workflows
mode: "monitoring"— pair with a scheduled Dify workflow that runs the actor weekly with awatchlistName. Thedelta.typeenum (new/changed/recovered/degraded) routes to different alert channels.mode: "compliance-screen"— pair with a Dify CRM-ingest workflow that screens new prospects at signup.decision == "escalate"blocks the signup;decision == "clear"lets it through.mode: "prospect-research"— pair with a B2B sales Dify workflow that filters ondonorTier IN ["mega-donor", "major"]for high-net-worth prospect lists.
Structured action arrays usable verbatim
The evidence[], counterEvidence[], reasons[], flags[], and verdictReasonCodes[] arrays are paste-ready into Dify LLM nodes for downstream summarisation — no rewriting needed. The summary field is the ≤280-char one-liner Dify prompts already truncate to.
Use cases
- Journalism and investigative reporting -- Track which individuals and corporations are funding specific candidates, PACs, or super PACs. Follow the money trail across election cycles.
- Political research and academia -- Build datasets of political contributions for analysis of donor demographics, giving patterns, geographic distribution, and partisan trends.
- Compliance and due diligence -- Verify whether individuals or companies have made political contributions as part of KYC, anti-corruption, or lobbying disclosure requirements.
- Nonprofit and advocacy -- Monitor campaign finance activity around specific issues, candidates, or legislative districts.
- Competitive intelligence -- Understand which politicians and committees are receiving funding from companies in your industry.
- Civic engagement tools -- Power apps and dashboards that help voters understand who funds their elected officials.
Programmatic access (API)
Python — compliance KYC screen:
from apify_client import ApifyClientclient = ApifyClient("YOUR_API_TOKEN")run = client.actor("ryanclinton/fec-campaign-finance").call(run_input={"mode": "compliance-screen","contributorName": "Elon Musk","electionYear": 2024,"maxResults": 100,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("recordType") != "contribution":continueif item.get("escalation", {}).get("level") == "immediate-review":print(f"ESCALATE: {item['contributorName']} (${item['amount']:,.0f}) -> {item['committeeName']}")print(f" Reasons: {item.get('reasons', [])}")
Python — sector aggregation:
run = client.actor("ryanclinton/fec-campaign-finance").call(run_input={"mode": "lobbying-intelligence","committeeName": "America PAC","groupBy": "sector","electionYear": 2024,"maxResults": 5000,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("recordType") == "aggregate":print(f"#{item['rank']} {item['groupLabel']}: ${item['totalAmount']:,.0f} "f"from {item['uniqueDonors']} donors ({item['sharePercent']}% of total)")
Python — graph extraction for Neo4j:
run = client.actor("ryanclinton/fec-campaign-finance").call(run_input={"mode": "graph","committeeName": "Forward Action PAC","electionYear": 2024,"maxResults": 5000,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("recordType") == "graph":print(f"Nodes: {item['nodeCounts']}")print(f"Edges: {item['edgeCounts']}")# Drop into Neo4j with `UNWIND` of item["nodes"] + item["edges"]
Python — cross-cycle partisan-shift detection:
run = client.actor("ryanclinton/fec-campaign-finance").call(run_input={"mode": "donor-profile","contributorName": "John Smith","crossCycleYears": [2020, 2022, 2024],"maxResults": 200,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("recordType") == "cross-cycle-profile" and item.get("partisanShiftDetected"):print(f"{item['contributorName']}: {item['shiftDirection']} "f"({item['shiftSeverity']}, {item['shiftConfidence']} confidence)")for line in item['shiftEvidence']:print(f" {line}")
JavaScript — monitoring with delta detection:
import { ApifyClient } from "apify-client";const client = new ApifyClient({ token: "YOUR_API_TOKEN" });const run = await client.actor("ryanclinton/fec-campaign-finance").call({mode: "monitoring",watchlistName: "high-risk-donors-q3-2024",contributorEmployer: "Acme Corp",electionYear: 2024,maxResults: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const changedOnly = items.filter(i => i.delta && i.delta.type !== "unchanged");for (const item of changedOnly) {console.log(`${item.delta.type}: ${item.contributorName} -> ${item.committeeName}`);console.log(` fields changed: ${item.delta.fieldsChanged.join(", ")}`);}
JavaScript — anomaly + cohort summary read:
const run = await client.actor("ryanclinton/fec-campaign-finance").call({mode: "opposition-research",candidateName: "Smith",electionYear: 2024,maxResults: 5000,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const anomalies = items.filter(i => i.recordType === "anomaly" && i.severity === "high");const cohort = items.find(i => i.recordType === "cohort-summary");console.log(`HIGH severity anomalies: ${anomalies.length}`);for (const a of anomalies) console.log(` ${a.anomalyType}: ${a.headline}`);console.log(`Cohort: ${cohort?.headline}`);
Legacy v1-style search (still supported):
const run = await client.actor("ryanclinton/fec-campaign-finance").call({mode: "raw",contributorEmployer: "Google",electionYear: 2024,minAmount: 5000,maxResults: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const item of items) {console.log(`$${item.amount.toLocaleString()} from ${item.contributorName} -> ${item.committeeName}`);}
cURL:
# Start a runcurl "https://api.apify.com/v2/acts/ryanclinton~fec-campaign-finance/runs" \-X POST \-H "Content-Type: application/json" \-H "Authorization: Bearer YOUR_API_TOKEN" \-d '{"searchMode": "contributions","contributorEmployer": "Google","electionYear": 2024,"minAmount": 5000,"maxResults": 500}'# Fetch results (after run completes)curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=json" \-H "Authorization: Bearer YOUR_API_TOKEN"
How it works -- technical details
Input (searchMode, filters, electionYear)│├── mode = "contributions" ├── mode = "candidates"│ │▼ ▼┌──────────────────────────┐ ┌──────────────────────────┐│ Schedule A Endpoint │ │ Candidates Endpoint ││ /schedules/schedule_a/ │ │ /candidates/search/ ││ │ │ ││ Filters: │ │ Filters: ││ • contributor_name │ │ • name ││ • committee_name │ │ • state ││ • contributor_employer │ │ • election_year ││ • contributor_state │ │ ││ • min_amount │ │ Sort: -receipts ││ • two_year_txn_period │ │ Pagination: page-based ││ │ │ (page=1, page=2, ...) ││ Sort: -contribution_amt │ │ ││ Pagination: cursor-based │ │ 100 per page, 500ms delay││ (last_index + last_amt) │ └─────────┬────────────────┘│ │ ││ 100 per page, 500ms delay│ │└─────────┬────────────────┘ ││ │▼ ▼┌─────────────────────────────────────────────┐│ Code Decoder ││ • Office: H→House, S→Senate, P→President ││ • Challenge: I→Incumbent, C→Challenger, ││ O→Open seat ││ • is_individual: boolean → isIndividual ││ • candidate_inactive: false → isActive: true│└──────────────────┬──────────────────────────┘│▼┌─────────────────────────────────────────────┐│ Output & Summary ││ • Each record → Apify dataset ││ Contributions: ││ • Total $ amount across all results ││ • Count of unique committees ││ Candidates: ││ • Parties represented │└─────────────────────────────────────────────┘
API endpoints
| Mode | FEC Endpoint | Sort | Pagination |
|---|---|---|---|
| Contributions | /v1/schedules/schedule_a/ | -contribution_receipt_amount (largest first) | Cursor-based: last_index + last_contribution_receipt_amount |
| Candidates | /v1/candidates/search/ | -receipts (most funded first) | Page-based: page=1, page=2, etc. |
Both endpoints use per_page=100 (API maximum) and a 500 ms delay between page requests to respect rate limits.
Cursor vs. page pagination
The FEC API uses cursor-based pagination for Schedule A contributions because this endpoint can return millions of records. Each response includes pagination.last_indexes with cursor values for the next page. The actor passes these as last_index and last_contribution_receipt_amount parameters on subsequent requests.
For candidates, the API uses standard page-based pagination with a page parameter and pagination.pages indicating total pages available.
Code maps
| Raw code | Decoded value | Field |
|---|---|---|
H | House | office |
S | Senate | office |
P | President | office |
I | Incumbent | incumbentChallenge |
C | Challenger | incumbentChallenge |
O | Open seat | incumbentChallenge |
How much does it cost to use?
| Scenario | Results | Pages | Time | Est. cost |
|---|---|---|---|---|
| Quick search | 100 | 1 | ~10 sec | ~$0.005 |
| Medium search | 500 | 5 | ~30 sec | ~$0.01 |
| Large dataset | 5,000 | 50 | ~2 min | ~$0.02 |
| Maximum extraction | 10,000 | 100 | ~3 min | ~$0.03 |
The FEC API is completely free. The actor runs on 256 MB of memory. Apify's free tier includes $5 of monthly platform usage.
Limitations
- 10,000 result maximum -- The actor caps at 10,000 results per run. For larger datasets, use date ranges or state filters to split across multiple runs.
- DEMO_KEY rate limit -- The default DEMO_KEY allows 1,000 API requests per hour. For high-volume use, register for a free FEC API key at api.open.fec.gov.
- Single-mode per run (contributions vs candidates) -- Each run operates in either contributions or candidates mode. To search both, run the actor twice with different
searchModevalues. - Filing lag -- FEC data depends on when campaigns file their reports. Quarterly and monthly filing deadlines produce data within days, but there can be gaps between filings.
- Uppercase names -- The FEC stores all names in uppercase. The raw
contributorNamereflects this; v2.x'sdonorCanonicalIdresolves name variants regardless of case. - PAC contributions may lack candidate linkage -- Donations to PACs, party committees, and other organizations may not have an associated candidate. The
candidateNameandcandidateIdfields will be null on those rows. - Schedule A only -- Only individual contributions are searched. Other filing types (Schedule B disbursements, Schedule E independent expenditures, etc.) are not included.
- External-feed coverage gaps -- Race competitiveness ratings (Cook / Sabato), full Census ZIP→County crosswalk, and real-time mid-cycle filings are NOT bundled. The actor ships a curated top-N metro/sector/elite-ZIP set covering ~80% of donor records by density; ZIPs outside the curated set return
metro: nullandisFlyover: true.
Aggregate analytics ARE supported as of v2.2 — set groupBy to receive recordType: "aggregate" records, or rely on the cohort-summary record's top-N lists.
Responsible use
- Campaign finance data is public record under federal law. However, use this data responsibly and avoid harassment or intimidation of donors.
- Follow the FEC API Terms of Service when using the data.
- Do not use the DEMO_KEY for production workloads. Register for a free API key to avoid impacting other users.
- When publishing donor data, provide appropriate context. Individual contributions do not necessarily reflect organizational positions.
- Be aware that contribution data does not prove quid pro quo relationships between donors and candidates.
FAQ
Do I need an API key? No. The actor works out of the box using the FEC's free DEMO_KEY, which allows 1,000 API requests per hour. For heavier usage, register for a free key at api.open.fec.gov.
What election years are available? The FEC API has data going back to the 1980s. You can search any even-numbered year (e.g., 2020, 2022, 2024). The most comprehensive data is for recent cycles.
Can I search for PAC and super PAC contributions? Yes. Use the committee name filter to search for specific PACs, super PACs, or other political committees. Contributions to these entities are filed as Schedule A receipts.
Why are some candidate fields null in contribution records? Not all contributions are linked directly to a candidate. Donations to PACs, party committees, and other organizations may not have an associated candidate. The committee information is always present.
How fresh is the data? The FEC updates its data regularly as campaigns file their reports. Quarterly and monthly filing deadlines typically produce data within days. The actor always queries live FEC data.
What is the difference between this and the FEC website? This actor provides the same data as fec.gov but in a structured, machine-readable format. You can automate searches, export to CSV/Excel, integrate with other tools via API, and process results programmatically.
Integrations and related actors
The output dataset can be exported in JSON, CSV, or Excel format, or accessed programmatically via the Apify API. Use webhooks to trigger automated workflows when a run completes.
| Related Actor | Description | Use with |
|---|---|---|
| Congress Bill Search | Search US congressional legislation | Cross-reference donors with legislative activity |
| Congressional Stock Trade Tracker | Track stock trades by members of Congress | Analyze financial activity alongside campaign funding |
| SEC EDGAR Filing Analyzer | Search SEC financial filings | Link corporate donors to public company filings |
| Federal Register Search | Search federal rules and regulations | Track regulatory activity alongside campaign funding |
| OFAC Sanctions Search | Search US Treasury sanctions list | Compliance screening of donors |
| SAM.gov Contract Monitor | Search federal contracts | Connect campaign donors to government contracts |
Connect with any Apify integration including Google Sheets, Zapier, Make (Integromat), Amazon S3, and custom API endpoints to build automated campaign finance monitoring workflows.