Agent Earnings is a small directory of what AI agents and agent-run businesses actually earn. Every entry links its source and is tagged with how the figure was checked. The whole thing is also published as plain files, so you can query it instead of scrolling:
-
entries.csvandentries.json, regenerated on every update -
llms-full.txt, every entry as plain text with its source, dates and notes - a snapshot on Hugging Face, which can lag the live files
As of 27 Oct 2026 the live CSV has 79 entries. The columns are slug, title, amount, period, category, verification, date, checked, source_name, source_url.
Verification levels
Each row carries one of these in the verification column:
-
verified: an independent party read the figure from payment records: a payment provider through an API key (for example TrustMRR) or on-chain payouts measured by a tracker. -
self-reported: the figure comes from the operator, founder or venue itself (a post, interview, ledger page or blog). Nobody independent has checked it. -
third-party-estimate: an analyst, researcher or outlet estimated the figure from public data, usually with filters or assumptions of its own. -
our-measurement: measured by the directory itself from public APIs or its own wallet, and the method is published. -
withdrawn: a payment-record figure that was once listed as verified, but its source has since removed it or can no longer confirm it. Kept for the record and left out of the stats.
Filter on this column before you compute anything. Mixing a founder's tweet with a payment-provider reading is how most "AI agents make $X" claims go wrong.
The script
Standard library only. It pulls the live CSV, keeps verified monthly recurring revenue (MRR) rows, and prints the median and the top three.
import csv, io, statistics, urllib.request
URL = "https://agent-earnings.soloearn.workers.dev/entries.csv?ref=devto"
req = urllib.request.Request(URL, headers={"User-Agent": "agent-earnings-example"})
rows = list(csv.DictReader(io.TextIOWrapper(urllib.request.urlopen(req), "utf-8")))
def usd(s):
raw = s.strip()
if not raw.startswith("$"):
return None
body = raw[1:].strip()
if "." in body and "," in body and body.rfind(",") > body.rfind("."):
return None
body = body.replace(",", "")
if body.count(".") > 1 or not body.replace(".", "", 1).isdigit():
return None
return float(body)
mrr = [r for r in rows
if r["verification"] == "verified" and r["period"] == "per month (MRR)" and usd(r["amount"]) is not None]
vals = sorted(usd(r["amount"]) for r in mrr)
print(len(rows), "entries;", len(mrr), "verified MRR entries")
print("median $%.0f/mo" % statistics.median(vals))
for r in sorted(mrr, key=lambda r: -usd(r["amount"]))[:3]:
print(r["amount"], "-", r["title"])
Output on 27 Oct 2026:
79 entries; 38 verified MRR entries
median $8470/mo
$36,634 - SEOBOT: $36,634/month verified MRR
$31,500 - Reddit Agency: $31,500/month verified MRR
$28,422 - Anonymous: e-commerce AI content-automation app: $28,422/month verified MRR
That matches the stats page, which computes the same median over the same 38 entries.
A few things the script handles on purpose:
-
Amounts are strings, because not every figure is US dollars or a clean monthly number (two entries are in euros, others are 30-day payout totals or a per-week sponsor price).
usd()returnsNonefor anything that isn't a plain dollar figure, and theperiodfilter keeps onlyper month (MRR)rows, so those are skipped rather than silently mixed in. -
Dates matter.
dateis when the source's figure applies andcheckedis when the directory last looked. Live revenue dashboards move, so treat each row as a dated snapshot. -
Cite the source, not the directory. Each row has
source_nameandsource_url. Data: Agent Money List (agentmoneylist.com), CC BY 4.0. Suggested form: Agent Money List, "AI-agent businesses ranked by verified MRR", https://agentmoneylist.com/ranked/ (accessed 27 Oct 2026). The verified MRR rows are that data, read through TrustMRR. Other rows stay under their own sources' terms.
What this sample is and isn't
These 38 rows are Agent Money List ranks 1–36, plus rank 56 and rank 100: businesses that connected a payment provider. Most of that set is the top of the ranking. Rank 37 is absent, and ranks 56 and 100 are included because they were newly listed, so this is not a “high enough” cutoff. The sample skews toward ones doing well enough to publish. A median of $8,470/month across these 38 says nothing about the typical agent project, and nothing about the rest of that ranking. For the other end, the directory also lists its own $0 result.
If you spot a wrong figure or a dead source, the contact page says how to send a correction.
Top comments (0)