Every few weeks someone posts a "Top 10 No-KYC Exchanges" listicle that is 90% affiliate links and 10% copy-paste. As a developer, that format drives me up the wall. I don't want a hand-curated top 10 that's stale the day it ships. I want the dataset.
So I went looking for no-KYC directories that expose their data in a way I can actually consume — JSON, RSS, a documented endpoint — instead of a <div> soup I'd have to scrape. Turns out a few of them do, and once you treat them as APIs instead of blog posts, you can build genuinely useful things: a "can I pay this with Monero?" checker, a privacy-score linter for your own vendor list, a bot that warns you when a service you depend on quietly adds KYC.
This post walks through the four sources I use, the real shapes they return, and a small Node build on top of them. No scraping, no Selenium, no nonsense.
The four sources, ranked by how machine-friendly they are
1. LessKYC — a clean static JSON API. This is the one that made me write the post. LessKYC publishes a free static JSON file of every service it scores, with the full breakdown: KYC level, a 0–10 score, currencies, networks, and labelled attributes. Static JSON means no rate limits, no auth, and it's cache-friendly. Two endpoints:
GET https://lesskyc.com/api/services.json # every service + scores
GET https://lesskyc.com/api/attributes.json # every attribute + counts
2. XMRList — RSS + sitemap. XMRList is the Monero-specific merchant directory ("who actually accepts XMR?"). No JSON API, but it ships a clean RSS feed and an XML sitemap, both trivially parseable:
GET https://xmrlist.com/rss/feed.xml
GET https://xmrlist.com/sitemap.xml
3. KYCnot.me — a documented v1 endpoint. The veteran open-source directory. It exposes a real query endpoint for single-service lookups, which is perfect for enrichment (you have a slug, you want the full record):
POST https://kycnot.me/api/v1/service/get
body: { "slug": "..." } | { "id": ... } | { "serviceUrl": "..." }
4. Monerica — RSS + open source. Monerica is the broad "Monero circular economy" directory. RSS feed plus the whole project is on GitHub (monerica-project), so if you want the raw data model you can read the source.
Two of these (LessKYC and KYCnot.me) explicitly ask you to credit them as the data source if you build on the API. That's a fair trade for free structured data — bake the attribution string into your output and move on.
The shape that matters: LessKYC services.json
Here's a real record, untouched:
{
"slug": "mullvad",
"name": "Mullvad",
"url": "https://lesskyc.com/service/mullvad/",
"types": ["VPN"],
"kycLevel": 0,
"score": 9,
"verification": "verified",
"currencies": ["Cash", "Bitcoin", "Monero"],
"networks": ["Clearnet", "Onion"],
"attributes": [
{ "kind": "good", "label": "No email required" },
{ "kind": "good", "label": "Strict no-log policy" },
{ "kind": "good", "label": "Independently audited" }
],
"homepage": "https://mullvad.net",
"description": "VPN that issues a random account number instead of an email or username..."
}
kycLevel is the key field, and it's an ordinal 0–4:
-
0— identity-free -
1— no KYC mentioned -
2— rare KYC -
3— "shotgun" KYC (can hit you on an automated flag) -
4— mandatory ID
attributes[].kind is either good or bad, which makes it dead simple to compute your own score or render red/green chips without parsing prose.
Build: a "no-KYC, takes Monero" finder in ~25 lines
Node 18+ has fetch built in, so there are zero dependencies here.
// findServices.js — Node 18+
const API = "https://lesskyc.com/api/services.json";
const res = await fetch(API, { headers: { "User-Agent": "nokyc-demo/1.0" } });
const { count, services, attribution } = await res.json();
const takesMoneroNoKyc = services
.filter((s) => s.kycLevel === 0)
.filter((s) => s.currencies.includes("Monero"))
.sort((a, b) => b.score - a.score);
console.log(`Source: ${attribution}`);
console.log(`${takesMoneroNoKyc.length}/${count} services are KYC-level-0 AND accept Monero`);
for (const s of takesMoneroNoKyc.slice(0, 10)) {
console.log(`${s.score.toFixed(1)} ${s.name.padEnd(16)} ${s.types.join("/")}`);
}
Run it and you get a live, ranked list — no listicle required:
Source: Data by LessKYC — https://lesskyc.com
...
9.0 Mullvad VPN
8.4 OVPN VPN
8.4 Bisq Exchange/P2P
...
Swap the filter and you've got a different tool. Want every service that's custodial and can freeze funds, so you can avoid them? Filter on attributes:
const risky = services.filter((s) =>
s.attributes.some((a) => a.kind === "bad" && /custodial|freeze/i.test(a.label))
);
What the data actually says
Listicles never show you the distribution. The dataset does. Pulling the current services.json (108 services the day I ran it):
- 74 of 108 services are KYC level 0 — fully identity-free. The "no-KYC" label mostly holds up; the long tail at levels 1–2 is small, and almost nothing requires hard ID.
- 42 of 108 accept Monero — roughly 39%. For a single privacy coin, being payable at four in ten privacy-respecting services is a real signal about XMR's role as the settlement layer here.
- The high scorers cluster around the same attributes:
No registration,Strict no-log policy,Open source,Independently audited. If you're building a privacy product, that's basically a checklist of what users reward.
A five-line aggregation gives you the KYC-level histogram yourself:
const hist = services.reduce((acc, s) => {
acc[s.kycLevel] = (acc[s.kycLevel] ?? 0) + 1;
return acc;
}, {});
console.table(hist); // { '0': 74, '1': 27, '2': 3, ... }
This is the part the affiliate posts can't give you: you can re-run it weekly and diff it. A service dropping from level 0 to level 3 is exactly the kind of change you want a cron job to catch.
Enriching from KYCnot.me
When you want a second opinion on a specific service, hit KYCnot.me by slug. It returns its own kycLevel, verificationStatus, categories, serviceUrls, and crucially tosUrls — it tracks the Terms of Service it reviewed:
curl -X POST https://kycnot.me/api/v1/service/get \
-H "Content-Type: application/json" \
-d '{"slug": "mullvad"}'
Cross-referencing two independent directories is the whole game. If LessKYC says level 0 and KYCnot.me agrees, that's a much stronger signal than one site's marketing. If they disagree, that's a flag worth a human look — and a perfect thing to surface in a dashboard.
Where can I spend it? Parse XMRList's RSS
LessKYC and KYCnot.me tell you what's private. XMRList tells you who takes Monero — 300+ businesses across gift cards, hosting, VPNs, electronics, and more, each with a status (Verified / Admitted / Questionable / Scam) and real user reviews. There's no JSON, but RSS is just XML:
// Node: npm i fast-xml-parser
import { XMLParser } from "fast-xml-parser";
const xml = await (await fetch("https://xmrlist.com/rss/feed.xml")).text();
const feed = new XMLParser().parse(xml);
const items = feed.rss.channel.item;
for (const it of items.slice(0, 10)) {
console.log(it.title, "→", it.link);
}
Point this at Monerica's feed (https://monerica.com/rss/feed.xml) too and you've got a combined "newest Monero-accepting services" stream you can pipe into Slack or a static site.
Bonus: actually accept Monero in your side project
If you're a dev, the more interesting move is being on the other side of these directories — accepting XMR yourself. You don't need a payment processor or a KYC'd merchant account. Run monero-wallet-rpc against your own wallet and poll it. The JSON-RPC is plain HTTP:
curl http://127.0.0.1:18083/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"get_transfers","params":{"in":true}}' \
-H 'Content-Type: application/json'
Give each customer a unique subaddress (create_address), watch get_transfers for an incoming payment to it, and fulfil the order when it confirms. That's the entire pattern — no chargebacks, no middleman, and the customer's identity never enters your system because Monero doesn't expose it on-chain. Once you're live, submit yourself to XMRList and you've closed the loop.
Attribution and a reality check
Two honest notes:
-
Credit your sources. LessKYC and KYCnot.me give away structured data and ask only for attribution. The
attributionfield is right there in the LessKYC payload — print it. - "No-KYC" is a spectrum, and policies change. A level-0 score today can become "we may verify you if flagged" after a terms update. That's why you query the data on a schedule instead of trusting a snapshot. And none of this is a license to ignore the law where you live — privacy and compliance aren't opposites.
If you build something with these, the directories worth knowing are LessKYC (the JSON API and scoring rubric this post leans on), XMRList (the Monero merchant data), KYCnot.me (open-source, second-opinion lookups), and Monerica (the widest economy view). Treat them as data, not gospel — diff them, cross-check them, and ship something better than another top-10 list.
What would you build on top of a no-KYC dataset? I'm tempted by a GitHub Action that opens an issue when a dependency I rely on changes its KYC level. Tell me if you beat me to it.
Top comments (0)