Free Data Breach API
If you are building something that needs data breach information, a security dashboard, a blog sidebar, a student project, a status page, you can take ours. It is static JSON on a CDN. There is no account to create, no key to rotate, no quota to watch and no paid tier waiting for you at the bottom of the page.
Start here
One request, no setup:
curl https://www.myrecon.xyz/data/v1/latest.json
Every endpoint is listed at /data/v1/index.json. Attribution to Have I Been Pwned is required by the licence, details below, and the embed widget handles it for you.
Endpoints
| Path | Returns |
|---|---|
/data/v1/index.json | Discovery document, every endpoint, counts, licence |
/data/v1/breaches.json | The full archive with total account figure |
/data/v1/breaches/{slug}.json | A single breach, a few hundred bytes |
/data/v1/latest.json | The ten most recently added, newest first |
/data/v1/case-files.json | Index of our long-form incident write-ups |
/data/v1/stats.json | Headline counters for a single-number display |
A breach record
Every payload shares an envelope, api_version, generated, licence, attribution: so you can write one parser for all of them. The records look like this:
{
"slug": "mckesson",
"name": "McKesson",
"title": "McKesson",
"domain": "mckesson.com",
"breach_date": "2026-08-21",
"added_date": "2026-09-10T05:45:39Z",
"accounts": 6404340,
"severity": 73,
"band": "Severe",
"verified": true,
"sensitive": true,
"stealer_log": false,
"data_classes": ["Email addresses", "Names", "Phone numbers", "..."],
"summary": "In August 2026, healthcare and pharmaceutical company ...",
"logo": "https://logos.haveibeenpwned.com/McKesson.png",
"url": "https://www.myrecon.xyz/breaches/mckesson.html"
}
| Field | Type | Meaning |
|---|---|---|
slug | string | Stable identifier. Use it as your key. |
breach_date | date | When the breach is believed to have occurred. |
added_date | datetime | When it entered the archive. Sort by this for "latest". |
accounts | number | Distinct accounts in the corpus, as reported upstream. |
severity | 0–100 | Our score, weighted by which data classes were exposed. |
band | string | Severe, Serious or Moderate: the score bucketed. |
verified | boolean | Upstream confirmed the corpus is genuine. Show this. |
sensitive | boolean | Membership alone could harm the person. Handle with care. |
stealer_log | boolean | From infostealer malware rather than a company breach. |
data_classes | string[] | Categories of data exposed, upstream's vocabulary. |
verified: false is not a detail to drop. An unverified breach is one nobody has confirmed is genuine, and presenting it beside confirmed incidents with no distinction is how a rumour becomes a fact on somebody's dashboard. If your interface has room for one boolean, make it this one.
Examples
Browser JavaScript
const res = await fetch("https://www.myrecon.xyz/data/v1/latest.json");
const data = await res.json();
for (const b of data.breaches) {
console.log(b.title, b.accounts, b.band);
}
Python
import urllib.request, json
url = "https://www.myrecon.xyz/data/v1/breaches.json"
with urllib.request.urlopen(url) as r:
data = json.load(r)
severe = [b for b in data["breaches"] if b["band"] == "Severe"]
print(len(severe), "severe of", data["count"])
One breach by slug
curl -s https://www.myrecon.xyz/data/v1/breaches/mckesson.json | jq .breach.data_classes
The embed widget
If you want a live breach list on your page and would rather not write the rendering, drop in two lines. It builds itself inside a shadow root, so your CSS cannot break it and it cannot leak styles into your page.
<div id="myrecon-breaches"></div>
<script src="https://www.myrecon.xyz/assets/js/embed.js"
data-count="5" data-theme="auto" async></script>
Options: data-count (1–10, default 5), data-theme (auto, dark, light), data-title.
It sets no cookies, stores nothing, and sends no identifier, it is one GET for a static file. If that request fails it renders nothing rather than showing your visitors an error. The attribution footer is drawn by the widget itself, which is what keeps you compliant with the licence without having to think about it.
Attribution: the part that is not optional
The breach data originates with Have I Been Pwned and is licensed CC BY 4.0. We redistribute it under that licence, and so do you when you publish it.
CC BY makes attribution a condition of use, not a courtesy. If you display this data publicly, credit Have I Been Pwned. That is the requirement, and it is owed upstream, we are the distributor, not the source. A link back to MyRecon is genuinely appreciated and is how this stays worth maintaining, but the licence does not demand it and neither do we.
A credit line that satisfies it:
Breach data from Have I Been Pwned (CC BY 4.0), via MyRecon.
Every JSON payload carries its own attribution object with the same information, so it travels with the data even if this page never gets read.
The case-file index is different: those write-ups are our own work. Use the index to link to them freely. Reproducing the article text needs a visible credit and a link to the article it came from.
Fair use, and what we ask
- Cache it. The data changes at most once a day. Fetch it on a schedule and serve from your own store rather than hitting us per page view, it is faster for your users and it is what the
generatedfield is for. - Do not hotlink the logos. The
logoURLs point at Have I Been Pwned's servers. Copy the images you need to your own hosting. - Parse defensively. New fields can appear in
v1without warning. Ignore keys you do not recognise. - Read the
generateddate. If your copy is a month old, say so in your interface rather than implying it is live.
What this API is not
It serves breach metadata: which incidents happened, what categories of data were exposed, how many accounts, how severe. It holds no personal records and cannot be queried by email address, name or password.
That is a deliberate boundary rather than a missing feature. Checking whether a specific address appears in breach data is a different operation with entirely different privacy implications, and an unauthenticated public endpoint is the wrong shape for it. That check lives on the tool, where it can be explained and consented to. If you need it programmatically, go to HIBP's own API, which is built for it.
Versioning and stability
The path carries the version. Additive changes, new fields, new endpoints, ship into /data/v1/ at any time, which is why you should ignore unknown keys. Anything that would break an existing consumer ships at a new version path, and v1 stays exactly where it is.
This is a free service maintained alongside a small product, offered in good faith and with no uptime guarantee. If you are building something where breach data being unavailable would be a real problem, cache it on your side.
Common questions
Is it really free?
Yes. No account, no key, no paid tier, no rate limit beyond fair use. The endpoints are static files on a CDN, so serving them costs almost nothing and there is nothing to meter.
Do I need to register?
No. Every endpoint is a plain GET with no authentication, and CORS is open, so browser JavaScript on any origin can call it directly.
How often does the data update?
The archive rebuilds from upstream daily, and each payload carries a generated date so you can see how fresh your copy is. The CDN caches for an hour and serves a stale copy for up to a day rather than failing.
Can I check a specific email address?
No, deliberately, see What this API is not above. Use HIBP's API for that.
Can I use this commercially?
CC BY 4.0 permits commercial use with attribution. Credit Have I Been Pwned as described above and you are within the licence.