Skip to content
THREATWIRE

API

Reference

Read this once if you have never called an API. Then copy one example. Every data route uses the same envelope.

  1. 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. 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. 3. Read data, then meta

    data is the record. meta.verification_status tells you whether ThreatWire reviewed it.

  4. 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.

Try a route

The key stays in this form. It is not written into the page or into local storage.

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