API
Reference
Read this once if you have never called an API. Then copy one example. Every data route uses the same envelope.
1. Create a key
Open Keys, sign in with the link we email you, and create a key. Copy it. ThreatWire shows it once.
2. Send it as a header
Authorization: Bearer tw_live_… goes on every data request. The public index at /api/v1 does not need it.
3. Read data, then meta
data is the record. meta.verification_status tells you whether ThreatWire reviewed it.
4. Follow the cursor
If pagination.next_cursor is set, request the same URL again with cursor= that value.
What a response looks like
{
"data": [ … ],
"pagination": { "limit": 20, "next_cursor": null },
"meta": {
"version": "v1",
"generated_at": "2026-10-19T12:00:00.000Z",
"provenance": "ThreatWire editorial CVE records.",
"verification_status": "editorial",
"last_verified": null
}
}- data
- The record, or a list of records.
- pagination.limit
- How many rows this page holds. The default is 20. The maximum is 50.
- pagination.next_cursor
- Pass this back as cursor to read the next page. Null means you are at the end.
- meta.version
- Always v1 for this API.
- meta.generated_at
- When this response was built.
- meta.provenance
- Where the record comes from, in one sentence.
- meta.verification_status
- Reviewed by ThreatWire, Public dataset — not yet independently reviewed, editorial, tracker snapshot, or mixed.
- meta.last_verified
- A date when ThreatWire has one. Otherwise null.
Two labels are exact. Reviewed by ThreatWire means ThreatWire checked the record. Public dataset — not yet independently reviewed means the public dataset, not a ThreatWire review. Unknown stays Unknown.
One example from each family
Replace tw_live_YOUR_KEY with the key from Keys. An assistant can use the same records through MCP.
/api/v1/cves
Published CVEs
Records ThreatWire has written. Filter with q, severity, kev=listed, or poc=yes.
curl -s "https://www.threatwire.tech/api/v1/cves/CVE-2026-64959" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/research
Research
Title, summary, category, and the article URL. The article body stays on the site.
curl -s "https://www.threatwire.tech/api/v1/research?category=news&limit=2" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/tracker/cves
Tracker snapshot
The broad CVE snapshot, including a public PoC flag. Pass q, or request one id. This does not return exploit links or code.
curl -s "https://www.threatwire.tech/api/v1/tracker/cves/CVE-2021-44228" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/defi/incidents
DeFi incidents
Reviewed records and the public dataset. Filter with q, chain, protocol, class, year, and verification.
curl -s "https://www.threatwire.tech/api/v1/defi/incidents?q=euler&year=2023&limit=1" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/defi/protocols
Protocols, chains, classes
The same indexes the site uses. Chains and classes have their own paths.
curl -s "https://www.threatwire.tech/api/v1/defi/chains?limit=5" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/defi/contracts
Addresses and transactions
Stored contracts and reviewed transactions. Lookup accepts address or tx.
curl -s "https://www.threatwire.tech/api/v1/lookup?address=0x0136fecf49e0217bfd2d9551e8e7b05f174ba8ec" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/defi/code
Code
File metadata. Lines are a second request and stop at 200 lines.
curl -s "https://www.threatwire.tech/api/v1/defi/code/guarded-delegation-pattern/lines?start=1&end=5" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/alerts
Alerts
The stored alert list. It is not a live monitor.
curl -s "https://www.threatwire.tech/api/v1/alerts?limit=5" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
/api/v1/search
Search and related
One query across stored records. Related returns sources attached to an id.
curl -s "https://www.threatwire.tech/api/v1/search?q=euler&limit=5" \ -H "Authorization: Bearer tw_live_YOUR_KEY"
When it does not work
Errors use problem+json, not the data envelope. The body has title, status, and detail.
- 400
- The query is too long, the page size is above 50, or a required field is missing.
- 401
- The key is missing, unknown, or revoked. Keys from old anonymous accounts stop on 19 November 2026.
- 403
- An account change came from another site, the bot check failed, or the account already has three active keys.
- 404
- That id is not in the store you asked.
- 410
- The old anonymous session route. Sign in with your email instead.
- 415
- An account change was not sent as application/json.
- 429
- A quota is used up: per key, per account (shared by all its keys), or per network. Retry-After says how long to wait.
- 503
- Key storage or sign-in email is not configured. This is a ThreatWire problem, not yours.
JavaScript
const res = await fetch("https://www.threatwire.tech/api/v1/cves?limit=2", {
headers: { Authorization: "Bearer tw_live_YOUR_KEY" },
});
if (!res.ok) throw new Error(await res.text());
const body = await res.json();
console.log(body.data, body.meta.verification_status);Python
import urllib.request
req = urllib.request.Request(
"https://www.threatwire.tech/api/v1/cves?limit=2",
headers={"Authorization": "Bearer tw_live_YOUR_KEY"},
)
print(urllib.request.urlopen(req).read().decode())Every path
- /api/v1
- /api/v1/openapi.json
- /api/v1/defi/incidents
- /api/v1/defi/incidents/{slug}
- /api/v1/defi/protocols
- /api/v1/defi/chains
- /api/v1/defi/classes
- /api/v1/defi/contracts
- /api/v1/defi/transactions
- /api/v1/defi/code
- /api/v1/defi/code/{slug}
- /api/v1/defi/code/{slug}/lines
- /api/v1/defi/lookup
- /api/v1/tracker/cves
- /api/v1/tracker/cves/{id}
- /api/v1/cves
- /api/v1/cves/{id}
- /api/v1/research
- /api/v1/research/{category}/{slug}
- /api/v1/alerts
- /api/v1/search
- /api/v1/related/{id}
- /api/v1/account
- /api/v1/account/login
- /api/v1/account/login/verify
- /api/v1/account/logout
- /api/v1/account/session
- /api/v1/account/keys
- /api/v1/account/keys/{id}/revoke
- /api/v1/account/usage