Technical writing

FEC Campaign Finance Enforcement: The Federal Database Behind Matters Under Review

· AI Analytics
FECCampaign FinanceEnforcementPolitical MoneyFederal Data

The Federal Election Commission Matters Under Review database tracks every campaign finance complaint and enforcement action—from contribution limit violations and disclosure failures to foreign national contributions and coordinated expenditure violations—with full case documents available via the FEC API.

The FEC and how it enforces campaign finance law

The Federal Election Commission was created by the Federal Election Campaign Act of 1971, substantially restructured by the 1974 FECA amendments enacted in the immediate aftermath of Watergate. Congress designed the FEC as a six-member bipartisan commission—no more than three members from the same political party—with commissioners nominated by the President and confirmed by the Senate to six-year terms. The bipartisan structure was intended to prevent either party from weaponizing the agency against its opponents. In practice, it has created a structural deadlock problem that shapes every enforcement decision the agency makes.

Taking any formal enforcement action requires four votes. With three Democrats and three Republicans on the commission, any matter where the two parties disagree on the merits produces a 3–3 tie. A tied vote is a no-action outcome: the Matter Under Review is closed without penalty, without a finding of probable cause, and without any public determination that a violation occurred. This outcome is common—particularly when the respondent is a major party actor, a presidential campaign, or a case with obvious partisan valence. The commission's own records show that deadlocked votes have increased over time, and multiple commissioners from both parties have publicly acknowledged that the structural design produces systematic under-enforcement.

When the commission does act, the process runs through the Office of General Counsel. OGC staff investigate complaints, review financial records, and produce a factual and legal analysis recommending whether probable cause exists to believe a violation occurred. If the commission votes to find probable cause (four votes required), OGC enters conciliation negotiations with the respondent. Most cases resolve through a conciliation agreement: the respondent pays a civil money penalty, agrees to cease the prohibited conduct, and in most cases enters a no-fault admission—acknowledging the factual record without admitting willful violation. If no conciliation agreement is reached, the commission may refer the matter to the Department of Justice for criminal prosecution (rare) or pursue a civil action in federal district court (rarer still). The overwhelming majority of resolved MURs end in conciliation.

The FEC opens approximately 350 to 500 new Matters Under Review per year. Resolution averages two to four years from the date a complaint is filed to the date a conciliation agreement is signed or the matter is dismissed. High-profile cases involving presidential campaigns or large financial institutions often run longer; routine disclosure failures by small committees resolve faster.

FECA violation types

The Federal Election Campaign Act defines several distinct categories of prohibited conduct. Understanding which type of violation a MUR involves is essential for interpreting the enforcement record.

Contribution limit violations

FECA imposes hard dollar limits on contributions to federal candidates, party committees, and PACs. For the 2024 election cycle, the limits were $3,300 per candidate per election—with primary and general elections treated as separate elections, so a donor could give $3,300 for the primary and another $3,300 for the general, for a cycle total of $6,600 to any single candidate. The limit to a national party committee was $41,300 per calendar year; contributions to the three national party committees combined (the separate accounts for presidential, Senate, and House candidates) were capped at $106,500 per year.

Super PACs, the independent expenditure-only committees created by Citizens United v. FEC (2010) and SpeechNow.org v. FEC (D.C. Circuit, 2010), may accept unlimited contributions from individuals, corporations, and unions for independent expenditures. What they may not do is make direct contributions to candidate committees or coordinate their spending with the candidates they support. The line between permissible “independent” spending and prohibited “coordinated” spending is the central legal dispute in the largest class of recent FEC enforcement actions. Corporations and unions are permanently prohibited from making direct contributions to candidate committees regardless of amount.

Disclosure failures

Political committees—candidate committees, PACs, super PACs, and party committees—are required to file periodic reports with the FEC disclosing their receipts and disbursements. Late filing triggers automatic administrative fines on a per-day schedule. More serious disclosure violations involve the failure to disclose the true identity of donors: using a business entity to shield an individual donor's identity, or accepting contributions without obtaining the required name, address, employer, and occupation information. The FEC's enforcement record on disclosure failures reflects a wide range, from clerical errors by small committees to deliberate concealment by large political operations.

Coordination

An expenditure made “in coordination with or at the request or suggestion” of a candidate or their authorized committee is treated as an in-kind contribution to that candidate. If the amount exceeds the applicable contribution limit, the coordination is a FECA violation. The legal test for coordination has been contested in FEC rulemaking and federal court for decades. The current rules use a two-part test: the communication must be paid for by someone other than the candidate, and it must involve either a “content standard” (the communication expressly advocates for or against the candidate) and a “conduct standard” (the content was produced using material nonpublic information from the campaign, or was made pursuant to a request from the campaign, or was made after substantial discussion with the campaign about the communication).

The coordination doctrine has produced some of the largest FEC enforcement actions in recent years. The 2016 Trump campaign case involving the National Enquirer and its parent company American Media Inc. turned on whether AMI's practice of “catch and kill”—purchasing stories about Trump to suppress them—constituted an in-kind contribution. The FEC ultimately found that AMI's $120,000 payment to suppress a story constituted an illegal corporate in-kind contribution to the Trump campaign and required AMI to pay a civil penalty.

Foreign national contributions

52 U.S.C. § 30121 prohibits foreign nationals—defined to include both foreign citizens and foreign governments—from contributing or donating money in connection with any election to public office. The prohibition extends to indirect contributions: a foreign national may not direct a domestic person or entity to make a contribution. Foreign national contribution cases have become more prominent as enforcement has tracked flows from foreign governments seeking influence in American political campaigns. Recent high-profile investigations have involved contributions linked to the United Arab Emirates (the Elliott Broidy and Tom Barrack prosecutions by the DOJ, with parallel FEC proceedings), Russian-linked money flows in the 2016 cycle, and various smaller cases involving individual foreign citizens who donated through U.S. entities they controlled.

Conduit contributions and straw donors

A conduit contribution—also called a straw donor scheme—occurs when one person or entity provides money to another for the purpose of making a contribution in the second person's name. The scheme is designed to circumvent contribution limits: a donor who has already given the maximum allowed to a candidate can funnel additional money through employees, family members, or business associates, each of whom appears on FEC records as an independent donor. The actual source of the funds is concealed.

The most consequential conduit contribution scheme in American political history was executed by Samuel Bankman-Fried and executives at his cryptocurrency exchange FTX. Between 2020 and 2022, Bankman-Fried directed more than $93 million in illegal contributions to federal candidates and political committees—the largest campaign finance violation ever prosecuted in the United States. The scheme worked by routing contributions through FTX employees, who received company funds, made political contributions in their own names, and were then reimbursed. Contributions went to candidates and committees of both parties, though the bulk of publicly visible contributions were routed through Democratic-leaning committees while contributions to Republican-aligned committees were directed through a business partner, Ryan Salame, who pleaded guilty separately. Bankman-Fried was convicted in November 2023 on seven federal fraud and conspiracy counts, with campaign finance violations among the underlying conduct.

Major FEC enforcement actions

Beyond the Bankman-Fried case, the FEC enforcement record includes several actions that illustrate the range of violations the commission has addressed.

Dinesh D'Souza, the conservative commentator and filmmaker, was charged in 2014 with making $30,000 in illegal contributions to the Senate campaign of Wendy Long (R-NY) by reimbursing associates who made contributions in their own names. D'Souza pleaded guilty to one count of making illegal contributions in the names of others, was sentenced to community service and probation, and received a presidential pardon in 2018. The FEC matter ran concurrently with the criminal prosecution.

The National Rifle Association has been the subject of multiple FEC complaints related to its activities in the 2016 election cycle. Complaints alleged that the NRA received funds from Russian nationals through its charitable arm and used those funds for political activities that should have been disclosed as foreign national contributions. The FEC has been unable to complete enforcement action in these matters due to repeated deadlocked votes, with Republican commissioners consistently voting not to pursue probable cause findings against the NRA.

The broader legal landscape has been reshaped by two Supreme Court decisions. Citizens United v. FEC (2010) held that the First Amendment prohibits the government from restricting independent political expenditures by corporations, associations, or labor unions, effectively striking down the prohibition on corporate independent expenditures that had been part of campaign finance law since 1907. Four years later, McCutcheon v. FEC (2014) struck down the aggregate biennial limits on contributions—the cap on the total amount a single donor could give to all federal candidates and committees combined in a two-year election cycle. Together, these decisions narrowed the scope of FECA's reach and increased the practical difficulty of enforcement by expanding the legal space in which money can flow without triggering a violation.

The MUR process in detail

A Matter Under Review begins when a complaint is filed with the FEC. Any person may file a complaint—there is no requirement that the complainant be a party to the alleged violation or have standing in the constitutional sense. In practice, most complaints are filed by opposing campaigns, party committees, or political watchdog organizations. Anonymous complaints are not permitted; the complainant must sign the complaint under oath.

Once a complaint is received and assigned a MUR number, the FEC notifies the respondents—the persons or organizations alleged to have violated the law. The respondents have 15 days to respond in writing, though extensions are routinely granted. The OGC then reviews the complaint, the response, and any additional evidence it can gather, and produces a recommendation to the full commission: either that there is reason to believe a violation occurred (recommending a finding of probable cause) or that there is no reason to believe a violation occurred (recommending dismissal).

If the commission votes, by four votes, to find reason to believe, OGC enters conciliation negotiations with the respondent. The standard conciliation agreement contains three elements: a civil money penalty; a statement of facts setting out what the respondent did; and a cease-and-desist provision. The vast majority of conciliation agreements include a no-fault admission—the respondent acknowledges the facts without admitting a willful violation. Willfulness would expose an individual respondent to criminal referral under 52 U.S.C. § 30109(d), which carries fines and up to five years imprisonment for knowing and willful violations of FECA's limits and prohibitions.

If no conciliation agreement is reached within a specified period (typically 90 days, with the commission able to extend), the commission may authorize OGC to file suit in federal district court. Civil suits by the FEC are rare. The more common outcome when conciliation fails is simply closure of the matter without action. If the four-vote threshold for any action cannot be reached—whether on probable cause, on conciliation, or on authorizing suit—the matter is dismissed and the respondent receives written notification that the FEC has closed the file.

Accessing MUR data via the FEC API

The FEC publishes its enforcement records through the OpenFEC legal search API at https://api.open.fec.gov/v1/legal/search/. The API requires an API key, available free from api.data.gov. The DEMO_KEY placeholder works for low-volume queries (approximately 30 requests per hour).

The primary enforcement endpoints are:

  • GET /v1/legal/search/?type=murs&q=foreign+national&api_key=DEMO_KEY — Full-text search across all MURs. The q parameter searches case names, subject matter, and disposition text. Useful for finding all MURs involving a specific violation type or respondent category.
  • GET /v1/legal/mur/{mur_number}/?api_key=DEMO_KEY — Full detail record for a specific MUR by number (e.g., 7940). Returns the complete case record including all dispositions, respondents, subjects, commission votes, and document links.
  • GET /v1/legal/search/?type=murs&case_status=Closed&per_page=100&page=1&api_key=DEMO_KEY — Paginated list of all closed MURs, most recent first.

Each MUR record in the API response contains the following key fields:

  • mur_number — The unique docket identifier (e.g., 7940). MUR numbers are assigned sequentially from the date the complaint is filed.
  • name — A descriptive case name, typically incorporating the respondent's name or the nature of the alleged violation.
  • open_date — ISO 8601 date when the MUR was opened (complaint received and docketed).
  • close_date — ISO 8601 date when the MUR was closed. Null for pending matters.
  • election_cycles — Array of election cycle years (e.g., [2016, 2018]) to which the alleged violations relate.
  • dispositions — Array of disposition objects, one per respondent. Each disposition contains: the respondent name, the penalty amount (in dollars, or zero for no-penalty dismissals), the disposition type (conciliation agreement, dismissal, no probable cause, or other), and the respondent's entity type (individual, committee, corporation, etc.).
  • commission_votes — Array of vote records showing how each commissioner voted on each motion. Includes votes on reason-to-believe, probable cause, conciliation approval, and dismissal. The commissioner names and their party affiliations are embedded in each vote record.
  • documents — Array of document objects linking to the PDF case files: complaint, factual and legal analysis, respondent responses, proposed conciliation agreement, final conciliation agreement, and closing letter. PDFs are served from https://www.fec.gov/files/legal/murs/.
  • subjects — Array of subject-matter tags from the FEC's internal taxonomy (e.g., “contribution limits,” “disclosure,” “foreign national contributions,” “coordination”).

The FEC also maintains a web-based enforcement search interface at fec.gov/data/legal/search/enforcement/ that exposes the same underlying data with filtering by case type, status, election cycle, respondent type, and keyword. For one-off lookups, the web interface is faster. For systematic analysis of enforcement patterns across hundreds of MURs, the API is necessary.

Python: analyzing the FEC enforcement record

The following script fetches recent closed MURs from the FEC legal API and computes five metrics: civil penalty totals by year, the distribution of respondent types, violation categories by keyword, the distribution of penalty amounts, and the average time from complaint to resolution.

import requests
import json
from datetime import datetime, date
from collections import defaultdict

# ── FEC Legal / Enforcement API ────────────────────────────────────────────────
# Register for a free API key at https://api.data.gov/signup
# DEMO_KEY works for low-volume queries (~30 requests/hour, 50/day).
API_KEY = "DEMO_KEY"
BASE    = "https://api.open.fec.gov/v1"


def fetch_closed_murs(page: int = 1, per_page: int = 100) -> dict:
    """Fetch a page of closed MURs from the FEC legal search endpoint."""
    params = {
        "api_key":    API_KEY,
        "type":       "murs",
        "case_status": "Closed",
        "per_page":   per_page,
        "page":       page,
    }
    r = requests.get(f"{BASE}/legal/search/", params=params, timeout=30)
    r.raise_for_status()
    return r.json()


def collect_murs(max_pages: int = 5) -> list[dict]:
    """Collect up to max_pages * 100 closed MURs."""
    murs = []
    for p in range(1, max_pages + 1):
        data = fetch_closed_murs(page=p)
        results = data.get("results", [])
        if not results:
            break
        murs.extend(results)
        print(f"  Page {p}: {len(results)} MURs fetched (total so far: {len(murs)})")
    return murs


def parse_date(s: str | None) -> date | None:
    if not s:
        return None
    for fmt in ("%Y-%m-%dT%H:%M:%S", "%Y-%m-%d"):
        try:
            return datetime.strptime(s[:19], fmt).date()
        except ValueError:
            continue
    return None


def penalty_by_year(murs: list[dict]) -> dict[int, float]:
    """Sum civil penalties by the year the MUR was closed."""
    totals: dict[int, float] = defaultdict(float)
    for mur in murs:
        close_date = parse_date(mur.get("close_date"))
        if not close_date:
            continue
        year = close_date.year
        for disp in mur.get("dispositions", []):
            for penalty in disp.get("penalties", []):
                amt = penalty.get("amount", 0) or 0
                totals[year] += float(amt)
    return dict(sorted(totals.items()))


def respondent_type_counts(murs: list[dict]) -> dict[str, int]:
    """
    Classify each MUR respondent into broad categories by inspecting
    the respondent name for keywords.
    """
    cats: dict[str, int] = defaultdict(int)
    keywords = {
        "Committee":  ["committee", "campaign", "pac", "fund"],
        "Individual": [],            # fallback if no other keyword matches
        "Party":      ["republican", "democratic", "democrat", "party", "rnc", "dnc"],
        "Corporation": ["inc", "llc", "corp", "company", "co.", "ltd"],
        "Union":      ["union", "local ", "afl", "seiu", "teamsters"],
    }
    for mur in murs:
        for disp in mur.get("dispositions", []):
            name = (disp.get("respondent", "") or "").lower()
            matched = False
            for cat, kws in keywords.items():
                if cat == "Individual":
                    continue
                if any(kw in name for kw in kws):
                    cats[cat] += 1
                    matched = True
                    break
            if not matched:
                cats["Individual"] += 1
    return dict(sorted(cats.items(), key=lambda x: -x[1]))


VIOLATION_KEYWORDS = {
    "Foreign National":   ["foreign national", "foreign", "non-citizen", "uae", "russia"],
    "Coordination":       ["coordinat", "coordinated expenditure", "in-kind"],
    "Disclosure Failure": ["disclosure", "reporting", "late filing", "failure to report"],
    "Contribution Limit": ["contribution limit", "excess", "over the limit", "$3,300", "$5,400"],
    "Conduit/Straw":      ["conduit", "straw donor", "reimburse", "bankman-fried", "ftx"],
}


def violation_categories(murs: list[dict]) -> dict[str, int]:
    """Count MURs by violation category using keyword matching on case name + subjects."""
    counts: dict[str, int] = defaultdict(int)
    for mur in murs:
        text = " ".join([
            (mur.get("name") or "").lower(),
            " ".join(mur.get("subjects", []) or []).lower(),
        ])
        for cat, kws in VIOLATION_KEYWORDS.items():
            if any(kw in text for kw in kws):
                counts[cat] += 1
    return dict(sorted(counts.items(), key=lambda x: -x[1]))


def penalty_distribution(murs: list[dict]) -> dict[str, int]:
    """Bucket civil penalties into size ranges."""
    buckets = {
        "$0 (no penalty)":       0,
        "$1 - $9,999":           0,
        "$10,000 - $49,999":     0,
        "$50,000 - $249,999":    0,
        "$250,000 - $999,999":   0,
        "$1M+":                  0,
    }
    for mur in murs:
        total_penalty = sum(
            float(p.get("amount", 0) or 0)
            for disp in mur.get("dispositions", [])
            for p in disp.get("penalties", [])
        )
        if total_penalty == 0:
            buckets["$0 (no penalty)"] += 1
        elif total_penalty < 10_000:
            buckets["$1 - $9,999"] += 1
        elif total_penalty < 50_000:
            buckets["$10,000 - $49,999"] += 1
        elif total_penalty < 250_000:
            buckets["$50,000 - $249,999"] += 1
        elif total_penalty < 1_000_000:
            buckets["$250,000 - $999,999"] += 1
        else:
            buckets["$1M+"] += 1
    return buckets


def avg_resolution_days(murs: list[dict]) -> float:
    """Average calendar days from open_date to close_date for MURs with both dates."""
    deltas = []
    for mur in murs:
        od = parse_date(mur.get("open_date"))
        cd = parse_date(mur.get("close_date"))
        if od and cd and cd > od:
            deltas.append((cd - od).days)
    return sum(deltas) / len(deltas) if deltas else 0.0


def main() -> None:
    print("Fetching closed MURs from FEC legal API...")
    murs = collect_murs(max_pages=5)
    print(f"\nTotal MURs collected: {len(murs)}")

    # (a) Penalties by year
    by_year = penalty_by_year(murs)
    print("\n=== Civil Penalties by Year (closed MURs) ===")
    for yr, total in by_year.items():
        print(f"  {yr}: ${total:>12,.0f}")

    # (b) Respondent types
    rtypes = respondent_type_counts(murs)
    print("\n=== Top Respondent Types ===")
    for cat, cnt in rtypes.items():
        print(f"  {cat:<20} {cnt:>5}")

    # (c) Violation categories
    vcats = violation_categories(murs)
    print("\n=== Violation Categories (keyword match) ===")
    for cat, cnt in vcats.items():
        print(f"  {cat:<25} {cnt:>5}")

    # (d) Penalty distribution
    dist = penalty_distribution(murs)
    print("\n=== Penalty Amount Distribution ===")
    for bucket, cnt in dist.items():
        print(f"  {bucket:<25} {cnt:>5}")

    # (e) Average resolution time
    avg_days = avg_resolution_days(murs)
    avg_years = avg_days / 365.25
    print(f"\n=== Average Resolution Time ===")
    print(f"  {avg_days:.0f} days  ({avg_years:.1f} years)")


if __name__ == "__main__":
    main()

The DEMO_KEY API key works for development and low-volume analysis. For production pipelines that need to collect the full MUR corpus (approximately 8,000 to 10,000 historical cases), register a free personal API key at api.data.gov/signup to avoid rate limiting. The full closed-MUR corpus can be collected in a few hundred API requests with per_page=100 pagination.

The dispositions array in each MUR record is the primary source for penalty data, but its structure is inconsistent across case age. MURs closed before approximately 2010 have less structured disposition records and may not carry machine-readable penalty amounts. For historical analysis predating the current API schema, the PDF documents themselves—particularly the final conciliation agreement—are the authoritative source and require text extraction.

What the enforcement record reveals

Analyzed in aggregate, the FEC enforcement record shows several consistent patterns. Contribution limit violations by individuals—typically donors who exceed the per-election limit or who contribute through multiple vehicles to circumvent aggregate limits—account for the largest category of resolved MURs by count, though not by penalty amount. Disclosure failures by small committees (late-filed reports, missing employer and occupation information) are the most numerous category of administrative fine proceedings.

The highest-penalty cases cluster in a narrow category: conduit and straw-donor schemes involving coordinated illegal contributions at scale, and corporate violations involving independent expenditure activity by prohibited entities. The Bankman-Fried case at $93 million in illegal contributions is not representative of the typical MUR; it is an outlier at the far extreme of the distribution. The median resolved MUR involves a penalty in the range of $10,000 to $75,000, most often for a disclosure failure or a relatively modest contribution limit overage.

The commission's structural deadlock is visible in the vote records. Filtering the API's commission_votes field to cases involving major-party presidential campaigns shows a markedly higher rate of 3–3 tie votes than the broader MUR population. Cases involving smaller actors—local candidates, minor party committees, individuals without direct party affiliation—resolve without deadlock at substantially higher rates. The pattern is consistent with the structural theory: the bipartisan commission is most likely to deadlock when the political stakes of enforcement are highest, and most likely to reach agreement when the respondent lacks the organizational resources to mobilize partisan protection on the commission.


Related: FEC campaign finance data · STOCK Act congressional trading

Part of the Federal Regulatory Data Hub.