API · v1

The public read API.

Every Advisory and CVE on this site, as JSON: list and filter them, fetch one by any id, or check a list of packages. No key needed; a free key gives you 10x the limits.

Base URL https://api.agentprime.io. Responses are JSON. Within v1, changes are additive only: new fields and new options, never a removed or renamed one.

Using Claude or another AI assistant? The MCP server at https://api.agentprime.io/mcp gives it these records and the package check as tools.

Basics

  • Read-only and public. Reads need no key; a free key raises your limits. Only published records and reviewed profiles are served; a source’s full description is never served, because it can contain exploit code.
  • Cached. Read responses are cached for 60 seconds, and for up to 5 minutes at our CDN, so a new record can take a few minutes to appear.
  • No browser access from other sites. CORS allows only agentprime.io, except for suggestions, which any page may read. Call the API from a server, a script or the command line.
  • Clean text. Summaries, names and other text from the sources come with invisible and bidirectional Unicode characters removed.
  • Errors are JSON, { "error": "…" }: 400 for a bad parameter, 401 for a wrong or revoked key, 404 for an unknown id, 413 for a body that’s too big, 429 over a limit, 503 when we’re busy, other 5xx when something is wrong on our side.

Limits

  • Per client, per minute: 120 reads, 30 searches (a list with q) and 30 checks (POST /v1/match). The MCP server’s searches and checks count towards the same limits.
  • With a key, per key, per minute: 1,200 reads, 300 searches and 300 checks, 10x the limits without one, wherever you call from. See Keys.
  • Over a limit you get 429 with Retry-After, in seconds. Wait that long, then retry.
  • Busy: when we can’t take a search or check right away, you get 503 with Retry-After. Retry after that.
  • Sizes: q is at most 100 characters (400 past it), and a /v1/match body at most 1 MB (413 past it).

Keys

Every endpoint works without a key. A free key gives you 10x the limits: requests with it count against the key, not your address.

  • Get one: sign in and create a key. Name it after where it’s used (“CI”, “Laptop”). The whole key is shown once; we keep only a hash of it, so copy it then. You can have several, see when each was last used, and revoke any of them.
  • Send it on any request as Authorization: Bearer <key>. Keys look like apk_<key id>_<secret>.
  • A wrong or revoked key gets 401 with a JSON error. It never falls back to the limits without a key, so a broken key shows up at once.
  • Revoking a key in your account stops it working at once.
  • Keep it secret. Send it from a server, a script or CI, never from a web page, and keep it out of repositories.
curl 'https://api.agentprime.io/v1/advisories?critical=true' \
  -H 'Authorization: Bearer apk_xxxxxxxxxxxx_…'
HTTP/1.1 401 Unauthorized
{ "error": "…" }

The same key works with the MCP server, where it also lets your assistant watch lockfiles.

List records

GET /v1/advisories

Newest first by when the source published each record, or most relevant first with q. Returns { data: AdvisorySummary[], next_cursor }; pass next_cursor back as cursor, with the same filters, for the next page. It’s null on the last page.

ParameterValuesDoes
kindpackage | cveOnly package Advisories, or only CVE records. Default both.
ecosystemnpm, Packagist, PyPI, Go, Maven, RubyGems, crates.io, NuGet, HexRecords affecting a package in this ecosystem (OSV’s names). Package records only.
packagenameRecords affecting this package. Add ecosystem to narrow.
frameworklaravel | nextjsThe framework and the packages its apps commonly install.
assignerCNA short nameOnly CVE records this CNA published, such as Wordfence or GitHub_M. Ignores case. Package records never match.
min_score0 to 10Only records whose severity.score is at least this. A record with no score never passes.
criticaltrueOnly critical records (see critical, below).
kevtrue | falseOnly records in (or not in) CISA’s Known Exploited Vulnerabilities list.
stateearly_warning, confirmed, withdrawn, retractedA comma list. Default all four.
qtextSearch, as in a web search engine: words must all match, "a phrase" in order, OR for alternatives, -word to exclude. Matches ids and aliases, package names, vendors and products, titles, descriptions and weakness types; part of a package or product name works too. Results come most relevant first: an exact id first, then the best matches, known-exploited and severe records ahead of others that match as well. At most 100 characters.
sortrelevance | newestWith q: most relevant first (the default), or newest first. Without q the order is always newest first.
tagslug or cwe-<n>Only records with this weakness tag, from their CWEs: sql-injection, xss, path-traversal, ssrf and others (see tags, below), or any CWE as cwe-79.
technologyslugOnly CVE records naming this vendor and product, such as fortinet-fortimail or linux-kernel (see technologies, below).
has_profiletrueOnly records with a reviewed Advisory profile.
includeaffectedAdds each record’s affected[] (OSV form). A CVE record’s is always [].
updated_sinceISO 8601 timeRecords changed at or after this time, oldest change first. For syncing.
limit1 to 500Page size. Default 100.
cursoropaqueThe next_cursor from the previous page, with the same filters.
curl 'https://api.agentprime.io/v1/advisories?critical=true&limit=20'
curl 'https://api.agentprime.io/v1/advisories?kind=package&ecosystem=npm&min_score=7'
curl 'https://api.agentprime.io/v1/advisories?kind=cve&q=CVE-2024-3094'
curl 'https://api.agentprime.io/v1/advisories?q=%22path+traversal%22+-wordpress'
curl 'https://api.agentprime.io/v1/advisories?tag=sql-injection&technology=fortinet-fortimail'

A summary looks like this (one record shown):

{
  "data": [
    {
      "id": "GHSA-xxxx-xxxx-xxxx",
      "kind": "package",
      "aliases": ["CVE-2026-12345"],
      "state": "confirmed",
      "summary": "Path traversal in example-package",
      "packages": [
        { "ecosystem": "npm", "package": "example-package",
          "affected_range": ">=2.0.0, <2.4.1", "fixed_versions": ["2.4.1"] }
      ],
      "published": "2026-10-30T14:02:11.000Z",
      "modified": "2026-10-30T14:02:11.000Z",
      "withdrawn": null,
      "first_seen_at": "2026-10-30T14:02:40.512Z",
      "updated_at": "2026-10-31T06:00:03.118Z",
      "profiles": [],
      "severity": { "score": 8.8, "version": "3.1",
        "vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
        "source": "ghsa", "rating": "HIGH" },
      "critical": { "reasons": ["cvss_high_epss"] },
      "signals": { "kev": null,
        "epss": { "score": 0.31, "percentile": 0.97, "date": "2026-10-31" } },
      "has_machine_summary": true,
      "url": "https://agentprime.io/advisories/GHSA-xxxx-xxxx-xxxx/"
    }
  ],
  "next_cursor": "WyIyMDI2LTEwLTMwVDE0OjAyOjExLjAwMDAwMFoiLCJHSFNBLS4uLiJd"
}

Sync changes

With updated_since, records come in the order they changed, (updated_at, id) ascending, and the time is inclusive, so records sharing a timestamp are never skipped across pages. updated_at moves on every change you’d care about: state, affected ranges or fixed versions, aliases, severity, CWE ids, a new source confirming it, a profile being reviewed or corrected. Records are never deleted, so this is all you need to keep a copy current. For package matching, add kind=package&include=affected.

# First run: everything, oldest change first
curl 'https://api.agentprime.io/v1/advisories?updated_since=1970-01-01T00:00:00Z&limit=500'
# Then follow next_cursor (same filters) until it is null
curl 'https://api.agentprime.io/v1/advisories?updated_since=1970-01-01T00:00:00Z&limit=500&cursor=…'
# Next run: from the last updated_at you saw. It's inclusive, so de-duplicate by id.
curl 'https://api.agentprime.io/v1/advisories?updated_since=2026-10-31T06:00:03.118Z&limit=500'

One record

GET /v1/advisories/:id

Any id or alias resolves: a GHSA, a CVE, a PYSEC or GO id. The response’s id is the canonical one (the GHSA when there is one), so compare against that. Unknown ids give 404.

curl 'https://api.agentprime.io/v1/advisories/GHSA-xxxx-xxxx-xxxx'
curl 'https://api.agentprime.io/v1/advisories/CVE-2026-12345'   # any alias resolves; "id" in the response is canonical

The detail has id, kind, advisory, severity, critical, signals, cwes, machine_summary, state, retracted_at and retraction_reason, first_seen_at, first_seen_via, updated_at, sightings[] (which source had it, and when), evidence[] (Early warnings only), profiles[] (reviewed only), page and url.

For a package record, advisory is the OSV-shaped Advisory without its description: affected[] with every range, and references[]. For a CVE record it’s the CVE’s own shape, with vendors, products and versions exactly as the CNA wrote them. No package ecosystem is ever inferred for a CVE.

"advisory": {
  "id": "CVE-2026-23456",
  "aliases": [],
  "summary": "SQL injection in the reporting module of Example Server",
  "published": "2026-10-29T09:15:00.000Z",
  "modified": "2026-10-30T11:20:00.000Z",
  "withdrawn": null,
  "cve_state": "PUBLISHED",
  "assigner": "ExampleCNA",
  "affected": [
    { "vendor": "Example Corp", "product": "Example Server", "default_status": "unaffected",
      "versions": [ { "version": "5.0", "status": "affected",
                      "version_type": "semver", "less_than": "5.2.3" } ] }
  ],
  "cwes": ["CWE-89"],
  "references": [ { "url": "https://example.com/security/2026-01", "tags": ["vendor-advisory"] } ],
  "cvss": [ { "version": "3.1", "score": 9.8, "source": "cna:ExampleCNA",
              "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" } ]
}

Suggestions

GET /v1/search/suggest?q=

What a search box offers as someone types: up to 8 of an exact id, weakness tags, technologies and packages whose names match q (2 to 100 characters), most records first. Each has kind (id, tag, technology or package), value (the id, slug or package name; packages add ecosystem), label, count and the url of its page here. It counts as a read, answers are cached for up to 10 minutes, and any website may call it from a browser.

curl 'https://api.agentprime.io/v1/search/suggest?q=forti'
{
  "data": [
    { "kind": "technology", "value": "fortinet-fortios", "label": "Fortinet FortiOS", "count": 412,
      "url": "https://agentprime.io/advisories/technology/fortinet-fortios/" },
    { "kind": "technology", "value": "fortinet-fortimail", "label": "Fortinet FortiMail", "count": 57,
      "url": "https://agentprime.io/advisories/technology/fortinet-fortimail/" }
  ]
}

GET /v1/search/facets lists every tag and the technologies with the most records, each with its count.

Check packages

POST /v1/match

Send a list of installed packages and get back the Advisories whose affected versions include them. This is what the lockfile check uses.

  • Request: { packages: [{ ecosystem, name, version }] }, with OSV ecosystem names (npm, Packagist, PyPI, Go, Maven, RubyGems, crates.io, NuGet, Hex) and exact installed versions. At most 5,000 packages per request.
  • Response: matches[], one entry per Advisory and package, with the Advisory’s affected entries for that package only, its fixed_versions, malicious and signals; unsupported[] for packages we can’t check, each with a reason; and checked_at.
  • What matches: package records only. CVE records, withdrawn and retracted Advisories never match.
  • Limits: 30 requests a minute per client (300 with a key), shared with the MCP checks; over that you get 429 with Retry-After. At most 1 MB per request (413 past it). See Limits.
  • CORS: only agentprime.io may call it from a browser.
  • Privacy: the request body is never logged or stored, including on errors.
curl -X POST 'https://api.agentprime.io/v1/match' \
  -H 'content-type: application/json' \
  -d '{"packages":[
        {"ecosystem":"npm","name":"example-package","version":"2.3.0"},
        {"ecosystem":"PyPI","name":"another-package","version":"1.0.4"}
      ]}'
{
  "matches": [
    {
      "advisory": {
        "id": "GHSA-xxxx-xxxx-xxxx",
        "aliases": ["CVE-2026-12345"],
        "summary": "Path traversal in example-package",
        "state": "confirmed",
        "url": "https://agentprime.io/advisories/GHSA-xxxx-xxxx-xxxx/",
        "affected": [ { "package": "example-package", "ecosystem": "npm", "versions": [],
                        "ranges": [ { "introduced": "2.0.0", "fixed": "2.4.1" } ] } ],
        "fixed_versions": ["2.4.1"],
        "malicious": false,
        "signals": { "kev": null, "epss": { "score": 0.31, "percentile": 0.97, "date": "2026-10-31" } }
      },
      "installed": [ { "ecosystem": "npm", "name": "example-package", "version": "2.3.0" } ]
    }
  ],
  "unsupported": [],
  "checked_at": "2026-10-31T12:00:00.000Z"
}

Fields

The fields most clients need, on summaries and details unless marked.

FieldTypeMeaning
kind"package" | "cve"A package Advisory (has packages; the only kind /v1/match returns), or a CVE List record that no package Advisory has. A CVE that is an alias of a package Advisory is merged into it and its id resolves there.
statestringearly_warning, confirmed, withdrawn or retracted. A rejected CVE is withdrawn and stays listed. Nothing is ever deleted.
severityobject | null{ score, version, vector, source, rating }. version is 4.0, 3.1, 3.0 or 2.0; rating is NONE, LOW, MEDIUM, HIGH or CRITICAL; source is cna:<CNA>, ghsa, osv or adp:<ADP>. One CVSS chosen from every source: the CNA’s own first, then GitHub’s or OSV’s, then an ADP’s (CISA’s Vulnrichment); CVSS 2.0 only when nothing newer exists. A 4.0 vector with no published score has score and rating null.
criticalobject | null{ reasons: ("kev" | "cvss_critical" | "cvss_high_epss")[] }. Critical when the record is in CISA KEV, or its CVSS is 9.0 or more, or its CVSS is 7.0 or more and its EPSS is 0.1 or more. Withdrawn and retracted records are never critical.
signalsobject{ kev: { date_added, ransomware } | null, epss: { score, percentile, date } | null }, joined through the record’s CVE ids. With several CVEs, the earliest KEV listing and the highest EPSS win.
machine_summaryobject | nullDetail only: { text, model, prompt_version, created_at }. Written by Claude Haiku from the source’s own description and not reviewed by a person. Summaries carry has_machine_summary (boolean) instead.
profilesarrayReviewed Advisory profiles only. Summaries give { package, approved_at }; the detail gives the full profile with approved_by, approved_at and corrections[].
tags{ slug, label }[]Weakness tags from the record’s CWEs, such as { slug: "sql-injection", label: "SQL injection" }. A CWE without a tag shows as { slug: "cwe-20", label: "CWE-20" }. Slugs never change; filter with tag=.
technologies{ slug, label }[]A CVE record’s vendors and products, such as { slug: "fortinet-fortimail", label: "Fortinet FortiMail" }. [] for package records. Filter with technology=.
cwesstring[]Detail only: CWE ids from every source (the CVE List, GitHub).
page.indexablebooleanDetail only: whether the record’s page on agentprime.io is indexed, which needs a reviewed profile.

The full list of fields, including the timeline’s sightings, is in each response; fields not listed here are stable too.

Versioning

Everything here is v1. Within v1 we only add: new fields, new filters, new values in a list of reasons. We never remove, rename or change the meaning of a field. Anything else would be a v2 at a new path, with time to move. Ignore fields you don’t know, and you’ll keep working.

Records come from the GitHub Advisory Database (CC-BY 4.0), OSV, the CVE List, NVD, CISA KEV and FIRST EPSS. If you publish them, credit the sources.