FEC Campaign Finance - Political Donations & Donors avatar

FEC Campaign Finance - Political Donations & Donors

Pricing

from $2.00 / 1,000 record fetcheds

Go to Apify Store
FEC Campaign Finance - Political Donations & Donors

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

Ryan Clinton

Maintained by Community

Actor stats

0

Bookmarked

10

Total users

1

Monthly active users

3 days ago

Last modified

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 identitydonorCanonicalId + entityResolutionConfidence survive 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-donor lifecycleStage across runs. By run 10 the actor knows which networks are durable; competitors can backfill data but cannot backfill historical memory.
  • Reproducibility hashesdecisionHash / classificationHash / evidenceHash SHA-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 + eventDedupKey for 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

StepQuestionWhat 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), and verdictReasonCodes[] (stable enum codes). Black-box scores never leave this actor.
  • Reproducible over heuristic driftrunManifest pins 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 + eventDedupKey for 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:

  1. Entity Intelligence — canonical donor + employer + committee identity that survives FEC's notoriously dirty input data.
  2. Network Intelligence — relationships, clusters, centrality, BFS traversal — the moat that raw lookup tools can't replicate.
  3. Temporal Intelligence — trajectory classification, deterministic forecasting, longitudinal memory, watchlist deltas across runs.
  4. 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

  1. Open the actor in Apify Console.
  2. Pick a moderaw for v1-style search; compliance-screen for KYC; opposition-research / lobbying-intelligence for analyst dossiers; intel-feed for Bloomberg-style monitoring; graph for Neo4j export; network-traversal for investigation; network-intelligence for the full v3.1 surface.
  3. Fill the search filters (contributorName, committeeName, contributorEmployer, contributorState, minAmount, electionYear).
  4. (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).
  5. 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

ParameterTypeDefaultDescription
searchModeselectcontributions"Individual Contributions" (Schedule A) or "Candidates" search.
contributorNamestringElon MuskDonor name to search for. Required for cross-cycle analysis.
candidateNamestring--Candidate name (candidates mode).
committeeNamestring--Filter by receiving committee/PAC (contributions mode).
contributorEmployerstring--Filter by donor's employer.
contributorStatestring--Two-letter state code (CA, TX, NY...). Works in both modes.
minAmountinteger--Minimum contribution amount in dollars.
electionYearinteger2024Federal election cycle year (even years).
maxResultsinteger100Maximum number of records to return (1–10,000).
apiKeystring (secret)DEMO_KEYFree FEC API key from api.open.fec.gov for higher rate limits.

Decision-engine inputs (v2.x)

ParameterTypeDefaultDescription
modeselectrawWorkflow preset — bundles persona + goal + outputProfile + watchlist + decision-engine flags. See mode preset table below.
personaselect(mode-derived)Output consumer — shapes which signals escalate and which are suppressed. See persona table below.
goalselect(mode-derived)Outcome shape — screening / dossier / monitoring / discovery / generic. Tightens or loosens flag thresholds.
outputProfileselect(mode-derived)Field shape per record — minimal / standard / full / llm.
watchlistNamestring--Persistent watchlist key for cross-run delta detection. Required for mode: "monitoring".
enableCohortSummaryboolean(mode-derived)Emit a cohort-summary record at end of run with totals + top employers/occupations/committees + partisan distribution + notable findings.
enableDecisionEngineboolean(mode-derived)Apply per-donor decision engine (tier / partisan-lean / max-out / risk / escalation). Off in raw mode.

Intelligence inputs (v2.1 / v2.2)

ParameterTypeDefaultDescription
enableInfluenceScoringbooleantrueCompute per-donor 0–100 influence score. Mirrored to DONOR_INFLUENCE_PROFILES KV.
enableGeoEnrichmentbooleantrueAdd metro / isSwingState / isEliteZip / isFlyover per record.
enableSectorClassificationbooleantrueClassify employer into a sector enum + emit sectorConfidence (0..1) + sectorMethod (direct-hit / startsWith / heuristic-pattern / no-match).
enableDataQualityReportbooleantrueEmit a data-quality record with coverage % per dimension + auditTrustLevel + weak-area callouts + unknown-sector employers + weak donor matches. Mirrored to COVERAGE_SUMMARY KV.
explainabilityLevelselectcompactVerbosity of per-record explanation fields. none = stripped (smallest payload), compact = top-2 evidence + reasons, full = entire decision trace.
enableRelationshipsbooleantrue(v3) Detect households / executive networks / bundler clusters / likely-spousal pairs. Emit recordType: "relationship-cluster" + edges. Mirrored to RELATIONSHIPS KV.
enableCentralitybooleantrue(v3) PageRank-style centrality on donor↔committee↔candidate graph. Mirrored to CENTRALITY KV (top-50 nodes).
enableEmergingDetectionbooleantrue(v3) Trajectory classification (emerging/accelerating/plateauing/declining/breakout). Emit recordType: "emerging-profile" records for breakouts. Mirrored to EMERGING_PROFILES KV.
enableNarrativesbooleantrue(v3) Emit typed recordType: "narrative" records with eventType / eventSeverity / eventDedupKey for downstream automation. Mirrored to NARRATIVES KV.
enableReproducibilityHashesbooleantrue(v3) decisionHash / classificationHash / evidenceHash SHA-256 digests per record. Compliance audit unlock.
enablePriorityRankingbooleantrue(v3.1) Collapse anomalies + narratives + emerging + clusters into one ranked list with priorityScore 0-100 + tier (P0–P3). Mirrored to PRIORITY_RANKING KV.
enableEliteClusterScoringbooleantrue(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.
enableForecastingbooleantrue(v3.1) Deterministic trajectory projections — likely-emerging-mega-donor / likely-future-bundler / cluster-expansion-likely / cooling-trajectory. Mirrored to FORECASTS KV.
enablePoliticalMemorybooleantrue(v3.1) Persistent network evolution across runs. Tracks cluster lifecycle + donor lifecycle in a separate named KV store. Requires watchlistName.
seedDonorstring--donorCanonicalId from a prior run. Required when mode: "network-traversal".
traversalDepthinteger2BFS depth from seed donor (1–5).
traversalEdgeTypesstring[](sensible defaults)Which relationship-edge types to traverse: same-household / likely-spousal / executive-network / donor-network / bundler-cluster / historical-association.
groupByselect--Aggregation engine — emit one recordType: "aggregate" per group (employer / committee / occupation / state / metro / sector / candidate / donor / committee-kind).
crossCycleYearsinteger[]--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

FieldTypeDescription
contributorNamestringFull donor name as filed (e.g., "MUSK, ELON")
contributorFirstNamestringDonor's first name
contributorLastNamestringDonor's last name
amountnumberContribution amount in US dollars
aggregateYtdnumberTotal amount the donor has given year-to-date to this committee
datestringDate of the contribution (YYYY-MM-DD)
committeeNamestringName of the receiving committee or PAC
committeeIdstringFEC committee ID (e.g., "C00873893")
candidateNamestring|nullAssociated candidate name, if linked (null for PAC/party donations)
candidateIdstring|nullFEC candidate ID, if linked
candidateOfficestring|nullOffice sought by the candidate (House, Senate, President)
candidatePartystring|nullCandidate's party affiliation
contributorEmployerstring|nullDonor's employer as reported
contributorOccupationstring|nullDonor's occupation as reported
contributorCitystring|nullDonor's city
contributorStatestring|nullDonor's state (2-letter code)
contributorZipstring|nullDonor's ZIP code
isIndividualbooleanWhether this is an individual (vs. organization) contribution
electionTypestring|nullElection type: GENERAL, PRIMARY, etc.
reportYearnumber|nullYear of the filing report
pdfUrlstring|nullDirect URL to the original PDF filing on FEC website
extractedAtstringISO 8601 timestamp of extraction

Candidate output fields

FieldTypeDescription
candidateIdstringFEC candidate ID (e.g., "P80001571")
namestringCandidate name as filed
partystringParty affiliation (e.g., "REPUBLICAN PARTY")
officestringOffice sought: House, Senate, or President (decoded from H/S/P codes)
statestringCandidate's state (2-letter code)
districtstringCongressional district (empty for Senate/President)
incumbentChallengestringIncumbent, Challenger, or Open seat (decoded from I/C/O codes)
isActivebooleanWhether the candidate is currently active
electionYearsnumber[]Array of election years the candidate has filed for
firstFileDatestring|nullDate of the candidate's first filing with FEC
hasRaisedFundsbooleanWhether the candidate has raised any funds
federalFundsbooleanWhether the candidate has received federal matching funds
extractedAtstringISO 8601 timestamp of extraction

How this compares to alternatives

NeedThis actorRaw FEC APIOpenSecretsManual workflow
Search contributions / candidates✅ deterministic decision verdict per record✅ raw 60-field JSON✅ web UI✅ slow
Donor canonical ID across name variantsdonorCanonicalId stable across runs
Employer normalisation✅ corporate suffixes stripped❌ raw FEC stringpartialmanual
Committee classification (Super-PAC / Leadership / Party / Hybrid)✅ stable enum + booleans⚠ committee_type code onlypartialmanual
Max-out detection vs federal individual cycle limitisMaxedOut + electionLimitStatusmanual
Partisan lean classification✅ strong-D / lean-D / mixed / lean-R / strong-Rpartialmanual
Persona-shaped escalation routing✅ 8 personas (compliance / journalist / oppo / lobby / procurement / etc.)
Anomaly detection (clusters, bundling, cross-party)✅ 9 deterministic patternsmanual
Per-donor cadence + velocity✅ burst / sustained / periodic + 30d/90d velocitymanual
Cross-run watchlist + delta✅ named-KV diff with 5 delta typesmanual
Graph output (Neo4j / Cytoscape)mode: "graph" returns nodes + edges
Cohort summary with top-N + narratives✅ employers / occupations / committees / statespartialmanual
Stable enum tokens for automation✅ recordType / decision / riskLevel / donorTier
AI-agent / Dify / n8n consumptionoutputProfile: "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.

ModeWhat it's forDefault persona
rawOriginal v1 search behaviour. No decisions, no cohort summary. Default.generic
due-diligenceKYC-style screening of a named individual. Decision verdict per record + cohort summary.compliance-officer
donor-profileDeep dossier on one donor: tier, partisan lean, employer concentration, max-out status.journalist
committee-watchProfile a candidate/committee's donor base — top employers, top occupations, partisan distribution.political-strategist
prospect-researchB2B sales mining — high-tier individual donors, employer-clustered, sortable by amount.sales-intelligence
compliance-screenStrict KYC/PEP — escalate on max-out, foreign address, PAC concentration. SLA-tightened.compliance-officer
monitoringCross-run change detection. Requires watchlistName. First run baselines; run 2+ surfaces deltas.compliance-officer
opposition-researchSurfaces controversial donors, cross-party giving, super-PAC bundling, employer clusters. Anomaly engine on by default.opposition-research
lobbying-intelligenceIndustry concentration + employer clusters + committee-influence mapping. Heavily weights employer/PAC concentration.lobbying-intelligence
graphEmit nodes (donors / employers / committees / candidates) + edges (donated_to / employed_by / committee_supports) for Neo4j / Cytoscape / NetworkX.generic
intel-feedBloomberg-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-intelligenceFull v3 — relationships + centrality + emerging-influence trajectory + narratives + cohort summary + everything. Deepest analysis tier.political-strategist
network-traversalInvestigation 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:

FieldDescription
donorCanonicalIdStable 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.score0..1 — share of donor identity fields populated. 5/5 fields = 1.0.
entityResolutionConfidence.levelhigh (≥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):

FieldDescription
employerCanonicalNormalised 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.
employerStatusStable enum: retired / unemployed / self-employed / homemaker / requested / employed / unknown. Filters out non-itemizable / pseudo-employer noise.
sector36-value enum derived from a curated lookup of ~250 top FEC employers + heuristic regex fallback (e.g. … UNIVERSITYeducation, … BANKcommercial-banking).
sectorConfidence0..1 — 1.0 for direct-hit, 0.85 for startsWith match, 0.5–0.65 for heuristic patterns, 0 for no-match.
sectorMethoddirect-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:

FieldDescription
committeeKindStable enum: authorized-candidate / leadership-pac / super-pac / hybrid-pac / party-national / party-state-local / separate-segregated / non-qualified-pac / unknown.
committeeKindLabelHuman-readable label.
isSuperPacTrue for FEC committee_type: "O" — accepts unlimited individual contributions.
isLeadershipPacTrue from FEC designation OR name pattern.
isPartyCommittee / isCandidateCommittee / isHybridPac / isPacConvenience booleans for direct equality matching in Dify / Zapier rules.

Filing intelligence

Fields present in the FEC response that v1 didn't surface:

FieldDescription
amendmentIndicatorFEC amendment code: N (new) / A (amendment) / T (termination).
isAmendedConvenience boolean — true when amendmentIndicator is A or T.
memoTextFEC memo text — often documents joint-fundraising context, attribution rules, or earmark notes.
memoCodeFEC memo code (X = no monetary effect — important for compliance sums).
reportTypeFEC report type code (M3 / Q3 / 12P / 30G / etc.).

Geographic enrichment

When enableGeoEnrichment: true (default):

FieldDescription
metroMSA name from ZIP3 lookup (~150 curated metros covering top US donor density). Null when ZIP not in curated set.
isSwingStateTrue when donor state is in PA / MI / WI / AZ / GA / NV / NC.
isEliteZipTrue for top-percentile mean-AGI ZIPs (curated from IRS SOI consensus).
isFlyoverTrue 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:

FieldTypeDescription
decisionenumclear / noted / flag / escalate. Stable.
decisionPostureenumauto-approve / manual-review / block. Stable.
decisionReasonstringSingle-sentence "decision · risk · materiality · top-reason" paste-ready justification.
riskLevelenumcritical / high / medium / low / none. Stable.
riskScore0–100Numeric risk.
materialityScore0–100Persona-weighted materiality.
donorTierenummega-donor (≥$50k cycle) / major ($10–50k) / large ($3.3–10k) / mid ($500–3.3k) / small (<$500).
isMaxedOutbooleanTrue 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.
electionLimitStatusenumunder / approaching (≥90%) / at-limit / over-limit / unknown.
partisanLeanenumstrong-D / lean-D / mixed / lean-R / strong-R / none.
isOutOfState / isForeignAddressbooleanDonor 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.
whyThisMattersstringPlain-English ≤200-char explanation.
summarystringPaste-ready ≤280-char one-liner.
shortReasonstringOne-phrase compressed reason for UI tiles / Slack messages.
escalationobjectlevel (immediate-review / standard-review / archive / ignore) + sla + audience[] + reason + ignoreRecommendation.
nextActions[]object[]Ranked sibling-actor calls with input hints (drives suite usage).
actorGraphobjectSuite navigation: previous / current / next[].
pipelineState / executionReadinessobjectWhat'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:

RelationshipTriggerOutput
Same-household2+ donors at same ZIP5 + same last namehouseholdCanonicalId per record + recordType: "relationship-cluster" (type: household)
Likely-spousalSame household + distinct first namessame-household edge upgraded to likely-spousal (strength 0.85)
Executive network2+ donors at same employer + senior title (CEO/VP/Founder/Partner/Director/etc.) + ≥$1k aggregateexecutiveNetworkId per record + cluster record
Bundler cluster5+ distinct donors at same employer in 14-day windowbundlerClusterId per record + cluster record + eventType: POLITICAL.BUNDLER_CLUSTER_DETECTED
Donor networkTwo donors who co-donated to ≥3 of the same committeesdonor-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:

FieldDescription
pagerankScore0..1 normalised
pagerankTiertop-1pct / top-5pct / top-10pct / top-25pct / rest
degree / weightedDegreeRaw + USD-weighted edge sums
crossSectorReachCount of distinct sectors touched
politicalReachIndex0–100 composite (pagerank × 50 + cross-sector × 4 + log10(weighted-degree) × 4)
explanationPlain-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:

ComponentWeightWhat it measures
density20%Cluster's share of cohort dollars
exclusivity10%Smaller, denser clusters score higher (3–12 members optimal)
centrality20%Average pagerank tier of members
crossSectorReach10%Distinct sectors touched
timingSynchrony15%Direct from cluster.timingTightness
committeeOverlap10%Concentrated targets = high overlap signal
seniorityDensity15%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 typeProperties
donordonorCanonicalId, isIndividual, donorTier, isMaxedOut, state, city, occupation, cycleAggregateYtd
employercanonical employer name
committeecommitteeId, committeeKind, isSuperPac, isLeadershipPac, isPartyCommittee
candidatecandidateId, party, office, state
Edge typeProperties
donated_tocount, totalAmount, firstDate, lastDate
employed_bycount, totalDonated
committee_supportscount

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:

FieldDescription
cadenceone-time / periodic / burst / campaign-window / sustained / unknown
firstSeen / lastSeenEarliest / latest contribution date in the cohort window
spanDaysDays between first and last seen
velocity30d / velocity90dSum of contributions in the last 30 / 90 days of the cohort window
velocityTrendaccelerating / steady / decelerating / unknown
avgGapDays / medianGapDaysGap 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:

FieldDescription
cyclesObserved / cyclesObservedCountElection years the donor appeared in
cycles[year]Per-cycle snapshot (lean, dShare, rShare, total, primary recipient)
overallLeanCross-cycle weighted partisan lean
partisanShiftDetectedBoolean — true when lean changed across cycles
shiftSeveritynone / minor / moderate / major
shiftDirectionD-to-R / R-to-D / partisan-to-mixed / mixed-to-partisan
shiftConfidencehigh (≥3 cycles + ≥5 contributions) / medium / low
shiftEvidence[]Per-cycle evidence strings paste-ready for stories / reports
longevityone-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:

TrajectoryTrigger
breakoutPrior aggregate <$1k AND now ≥$10k AND velocity ≥3×
acceleratingVelocity ≥1.5× recent vs prior + network expansion ≥1.3×
plateauingVelocity 0.8–1.2×, ≥3 contributions
decliningVelocity <0.7× of prior pace
emergingFirst-time observation with ≥$5k aggregate
unknownInsufficient 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 TypeTrigger
likely-emerging-mega-donorBreakout trajectory + emergingInfluenceScore ≥70 + tier in {major, large}
likely-future-bundlerExecutive-network cluster + ≥3 members + seniorityShare ≥0.5 + timingTightness ≥0.4
cluster-expansion-likelyBundler-cluster + committeeDiversification ≥0.5
cooling-trajectoryDeclining 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 / degraded
  • recovered: prior decision was flag / escalate, current is clear / noted (impact: high)
  • degraded: prior decision was clear / noted, current is flag / escalate (impact: high)
  • delta.fieldsChanged[] — which fields shifted
  • delta.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 / runsSeen
  • historicalMemberDonorIds — union of memberships across all runs
  • totalContributedUsdMax — peak across runs
  • persistence: transient (1 run) / recurring (≥2) / durable (≥5) / institutional (≥10) — stable enum

Per-donor lifecycle (mirrored to DONOR_LIFECYCLE KV):

  • firstSeenAt / lastSeenAt / runsSeen
  • cumulativeAmount / cumulativeContributions (across runs, not just current cohort)
  • distinctCommitteesEverSeen / distinctEmployersEverSeen
  • memberOfClusterIds[] — union of cluster memberships ever
  • lifecycleStage: 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:

PatternTriggerSeverity
multi-committee-burstSingle donor → 5+ distinct committees within 30 dayshigh
super-pac-bundlingSingle donor → 3+ super-PACs within 30 dayshigh
cross-party-donorDonor gave to BOTH Democratic and Republican candidates this cyclemedium
rapid-sequential-donations3+ donations in <72 hours from same donormedium
high-frequency-donor>20 contributions from same donor in cohort windowmedium
cross-committee-saturationDonor → super-PAC + party-national + leadership-PAC simultaneouslymedium
employer-cluster3+ employees of same employer → same committeehigh
coordinated-timing-cluster3+ employees of same employer donating within 7-day windowmedium
max-out-cluster3+ maxed-out donors at same employerhigh

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.

FieldDescription
narrativeTypeStable 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.
headlinePaste-ready exec-line ("Senior executives at Goldman Sachs activated as a coordinated political network, contributing $2.1M across 14 executives.")
detailLong-form context
confidencehigh / medium / low
drivers[]Plain-English drivers
evidence[]Specific data points supporting the synthesis
eventType / eventSeverity / eventDedupKeyAutomation-grade routing primitives
affectedDonorIds[] / affectedEmployers[] / affectedCommitteeIds[]Linkage back to source records
metricUsdAnchor 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":

FieldDescription
priorityScore0–100 composite (base score per record-type × severity weight × confidence boost × dollar boost)
priorityTierP0-investigate-now (≥75) / P1-this-week (≥55) / P2-monitor (≥35) / P3-archive. Stable enum.
sourceRecordTypeWhich kind of record this priority entry was derived from.
sourceIdStable 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 lines
  • topEmployers / topOccupations / topCommittees / topStates — top-5 by amount with count + share
  • topDonors — top-10 by cycle aggregate
  • partisanDistribution with leanLabel
  • donorTierDistribution / decisionDistribution / flagDistribution
  • maxOutCount / foreignAddressCount / outOfStateCount
  • cohortRiskLevel / cohortDecision / decisionReadiness / confidenceLevel
  • notableFindings[] — 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:

FieldDescription
groupKey / groupLabelStable key + human-readable label
contributionCount / uniqueDonors / uniqueCommitteesCardinality
totalAmount / avgAmount / medianAmountAmount stats
maxOutCount / foreignAddressCountRisk indicators
decisionDistribution / partisanDistribution / partisanLeanCohort-level decision/partisan rollup
flags[]Top-5 flags by frequency
sharePercentGroup's share of cohort total
rankPosition 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:

FieldDescription
influenceScore0–100 composite
influenceTiermega-influence (≥80) / high-influence (≥60) / mid-influence (≥40) / low-influence (≥20) / minimal
componentsamount 30% / spread 20% / committeeImportance 20% / candidateTargeting 15% / velocity 10% / maxOut 5% (documented weight pack)
weightsExposed 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:

HashInputs
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

ProfileIncludes
minimalrecordType, decision, riskLevel, donorTier, isMaxedOut, partisanLean, summary + key identity
standardminimal + raw FEC fields + decision details + escalation + nextActions (default for most modes)
fulleverything internal
llmminimal + whyThisMatters + reasons + flags + confidence + actorGraph + nextActions

explainabilityLevel controls per-record verbosity:

LevelWhat ships
noneStrips evidence / counterEvidence / reasons / whyThisMatters / materialityComponents / decisionTrace / verdictReasonCodes. Smallest payload.
compact (default)Top-2 evidence + top-2 reasons + summary / whyThisMatters.
fullEntire 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 / memoTextPresentPct
  • weakAreas[] — plain-English coverage gaps ready to paste into a Slack alert
  • unresolvedEmployers[] — top-5 records where employer was missing
  • unknownSectorEmployers[] — top-10 employers whose sector classification returned no-match (candidates for adding to the curated lookup)
  • weakDonorMatches[] — top-10 donors with entityResolutionConfidence.score < 0.5 (high false-positive risk on cross-cycle joins)
  • auditTrustLevel: high / medium / lowproduction-automation gate
  • auditTrustReason — 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.

PersonaWhat it surfacesSuppressesDefault audience tags
compliance-officermax-outs, foreign addresses, PAC concentration, aggregate-limit-exceeded. SLA tightened.partisan-leancompliance / kyc / aml
journalistlarge amounts, partisan flips, employer clusters.newsroom / oppo-research
sales-intelligencemega/major-donor tier, employer concentration, large amounts.foreign-address, partisan-leansales / sdr / go-to-market
political-strategistpartisan intensity, committee concentration, cross-cycle shift.campaign / opposition-research
opposition-researchcross-party donors, super-PAC bundling, max-out behaviour, employer clusters.campaign / opposition-research / newsroom
lobbying-intelligenceemployer concentration, PAC concentration, cross-committee saturation.partisan-leanpolicy / lobbying / regulatory
procurement-officervendor max-outs, foreign addresses, super-PAC bundling — for conflict-of-interest review.procurement / compliance / government-contracts
genericeven 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 / error
  • decision: clear / noted / flag / escalate
  • decisionPosture: auto-approve / manual-review / block
  • riskLevel: critical / high / medium / low / none
  • donorTier: mega-donor / major / large / mid / small
  • partisanLean: strong-D / lean-D / mixed / lean-R / strong-R / none
  • electionLimitStatus: under / approaching / at-limit / over-limit / unknown
  • escalation.level: immediate-review / standard-review / archive / ignore
  • committeeKind: authorized-candidate / leadership-pac / super-pac / hybrid-pac / party-national / party-state-local / separate-segregated / non-qualified-pac / unknown
  • sector: 36-value enum (see Pillar 1)
  • employerStatus: retired / unemployed / self-employed / homemaker / requested / employed / unknown
  • narrativeType: see Pillar 4
  • forecastType: likely-emerging-mega-donor / likely-future-bundler / likely-network-activation / probable-committee-migration / cooling-trajectory / cluster-expansion-likely
  • trajectory: breakout / accelerating / plateauing / declining / emerging / unknown
  • persistence: transient / recurring / durable / institutional
  • lifecycleStage: new / returning / sustained / durable
  • priorityTier: P0-investigate-now / P1-this-week / P2-monitor / P3-archive
  • significanceTier: institutional / high / notable / background
  • pagerankTier: top-1pct / top-5pct / top-10pct / top-25pct / rest
  • delta.type: new / changed / unchanged / recovered / degraded
  • eventType: 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.com territory.
  • 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 ticket
ELSE IF decision == "flag" AND donorTier IN ["mega-donor", "major"]
→ branch: enrich with ryanclinton/person-enrichment-lookup
ELSE IF decision == "noted" AND isMaxedOut == true
→ branch: add to watchlist for next run
ELSE
→ branch: archive

Boolean gates that work as direct equality matches in Dify:

  • isMaxedOut — donor hit the federal individual cycle limit
  • isForeignAddress — donor address fails US-state validation (compliance flag)
  • isOutOfState — donor state ≠ candidate state
  • escalation.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].inputHint
Step 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 a watchlistName. The delta.type enum (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 on donorTier 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 ApifyClient
client = 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":
continue
if 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 run
curl "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

ModeFEC EndpointSortPagination
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 codeDecoded valueField
HHouseoffice
SSenateoffice
PPresidentoffice
IIncumbentincumbentChallenge
CChallengerincumbentChallenge
OOpen seatincumbentChallenge

How much does it cost to use?

ScenarioResultsPagesTimeEst. cost
Quick search1001~10 sec~$0.005
Medium search5005~30 sec~$0.01
Large dataset5,00050~2 min~$0.02
Maximum extraction10,000100~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

  1. 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.
  2. 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.
  3. 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 searchMode values.
  4. 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.
  5. Uppercase names -- The FEC stores all names in uppercase. The raw contributorName reflects this; v2.x's donorCanonicalId resolves name variants regardless of case.
  6. PAC contributions may lack candidate linkage -- Donations to PACs, party committees, and other organizations may not have an associated candidate. The candidateName and candidateId fields will be null on those rows.
  7. Schedule A only -- Only individual contributions are searched. Other filing types (Schedule B disbursements, Schedule E independent expenditures, etc.) are not included.
  8. 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: null and isFlyover: 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.

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 ActorDescriptionUse with
Congress Bill SearchSearch US congressional legislationCross-reference donors with legislative activity
Congressional Stock Trade TrackerTrack stock trades by members of CongressAnalyze financial activity alongside campaign funding
SEC EDGAR Filing AnalyzerSearch SEC financial filingsLink corporate donors to public company filings
Federal Register SearchSearch federal rules and regulationsTrack regulatory activity alongside campaign funding
OFAC Sanctions SearchSearch US Treasury sanctions listCompliance screening of donors
SAM.gov Contract MonitorSearch federal contractsConnect 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.