Npm Dataset API (Beta)
The Npm Dataset API (Beta) is a new generation of the Threat Intelligence API, currently available to selected partners working directly with Patchstack. It lives alongside the v2 API (Standard / Extended) and adds npm coverage, an optional full advisory body, a consistent nested response shape, and cursor pagination. If you’d like access to run an integration on Beta, contact us.
Interactive reference: Every endpoint, parameter, request body and response shape is documented in the Threat Intelligence API (Beta) reference.
This page covers the concepts you need to use the API effectively — authentication, platforms, pagination, rate limiting, and migration from v2. Use it alongside the interactive reference.
Use with Postman, Insomnia, Bruno or Hoppscotch
Section titled “Use with Postman, Insomnia, Bruno or Hoppscotch”We publish the API as an OpenAPI 3.1 spec and a pre-built Postman collection. Every endpoint, parameter, request body and example is preconfigured — set your PSKey once and the whole collection authenticates.
Download the collection and drag it into Postman/Insomnia/Bruno/Hoppscotch, or import it by URL from inside the tool.
| Tool | How to import |
|---|---|
| Postman | File → Import → Link and paste the collection URL. |
| Insomnia | Create → Import From → URL → paste the OpenAPI URL. |
| Bruno | Collection → Import → OpenAPI V3 Spec → paste the OpenAPI URL. |
| Hoppscotch | Collections → Import/Export → OpenAPI → paste the OpenAPI URL. |
Authentication: in Postman set the collection Authorization to API Key, key PSKey, value {{PSKEY}}, and add PSKEY as a collection variable with your real key as the Current value (leave Initial blank so it doesn’t sync to teammates). Other tools work the same way — set PSKey as a collection header once.
Use with Claude Code or other LLM coding assistants
Section titled “Use with Claude Code or other LLM coding assistants”Point your assistant at the spec. LLMs parse OpenAPI cleanly and will generate clients that match the real field names instead of hallucinating.
- Ad hoc: paste the spec URL into your prompt. Example: “Write a Python client for
https://docs.patchstack.com/schemas/threat-intel-beta.yaml. I need cursor-mode iteration over/allfor npm.” - In your repo: download the spec to
docs/vendor/patchstack-threat-intel-beta.yamland reference it from yourCLAUDE.md/AGENTS.md. Your assistant can then grep the YAML for specific fields without refetching. - Plain-text fallback: for tools that don’t parse YAML, our
llms-full.txtcontains the full reference as flat markdown.
SDK generation
Section titled “SDK generation”Generate a client in any language from the same spec:
# TypeScriptnpx @openapitools/openapi-generator-cli generate \ -i https://docs.patchstack.com/schemas/threat-intel-beta.yaml \ -g typescript-fetch -o ./patchstack-client
# Pythonnpx @openapitools/openapi-generator-cli generate \ -i https://docs.patchstack.com/schemas/threat-intel-beta.yaml \ -g python -o ./patchstack-client-pySpeakeasy and Fern also consume the same spec and produce more idiomatic SDKs if you need a polished client library.
Spec stability: the Beta spec may change without a version bump while the API is in beta. Pin a commit of the YAML in production integrations, or wait for the GA release when we’ll publish versioned URLs.
Base URL
Section titled “Base URL”https://vdp-api.patchstack.com/database/api/beta/Authentication
Section titled “Authentication”Every request must include your API key in the PSKey HTTP request header. You can request an API key by reaching out on https://patchstack.com/for-hosts/.
PSKey: <your-api-key>Platforms
Section titled “Platforms”Pass ?platform=npm (or ?platform=wordpress — the default) on list endpoints. Platform names are case-insensitive.
Response format
Section titled “Response format”All responses are JSON. Beta responses are cached until the database updates, at which point the cache is cleared. A single response shape is shared across all three list endpoints (/all, /latest, /product/npm/...) so clients can parse them interchangeably.
Pagination
Section titled “Pagination”/all and /latest support two independent pagination strategies. Use whichever fits your client:
- Offset (
?page=&per_page=) — returns apaginationblock with totals,has_next_page,has_previous_page, etc. Easy to jump to a specific page; slower at depth and susceptible to row-shift when new vulnerabilities land while you’re paging. - Cursor (
?cursor=) — returns acursorblock withnext_cursor,has_more,per_page. Stable under concurrent inserts and faster at any depth. Nototalcount (deliberately skipped to keep cursor mode fast).
cursor and page are mutually exclusive; passing both returns 422 Unprocessable Entity. To bootstrap cursor mode, send ?cursor= with an empty value.
Including full advisory bodies
Section titled “Including full advisory bodies”Pass ?include=details on any list endpoint to add an advisory_details markdown field to each item. Applies to npm results.
Scoped npm packages
Section titled “Scoped npm packages”npm package slugs that include a / (e.g. @scope/pkg) conflict with the route separator. URL-encode the / as %2F or contact us for guidance on the encoding helper.
Rate limiting
Section titled “Rate limiting”Same policy as the Extended Threat Intelligence API — please contact https://patchstack.com/for-hosts/ if you need an elevated quota.
Errors
Section titled “Errors”| Status | Meaning |
|---|---|
401 Unauthorized | Missing or invalid PSKey header. |
403 Forbidden | API key not authorised for the requested endpoint. |
422 Unprocessable Entity | Invalid parameter combination (e.g. cursor + page), invalid platform, or per_page > 500. |
429 Too Many Requests | Rate limit exceeded. |
500 | Server error — please include the request id in any bug report. |
When a cursor is malformed (invalid base64 or missing the v1: prefix), the endpoint returns 200 with an empty page:
{ "vulnerabilities": [], "cursor": { "next_cursor": null, "has_more": false, "per_page": 100 }}Testing
Section titled “Testing”curl — one-liners
Section titled “curl — one-liners”# Latest 24h, npmcurl 'https://patchstack.com/database/api/beta/latest?platform=npm&per_page=10' \ -H 'PSKey: <your-api-key>'
# Cursor pagination walk (bootstrap + follow)curl 'https://patchstack.com/database/api/beta/all?platform=npm&per_page=50&cursor=' \ -H 'PSKey: <your-api-key>'
# Check a specific npm package/version with full advisory textcurl 'https://patchstack.com/database/api/beta/product/npm/axios/0.21.4?include=details' \ -H 'PSKey: <your-api-key>'
# Boolean-only exists checkcurl 'https://patchstack.com/database/api/beta/product/npm/axios/0.21.4/exists' \ -H 'PSKey: <your-api-key>'Postman / Insomnia / Bruno / Hoppscotch
Section titled “Postman / Insomnia / Bruno / Hoppscotch”Import the OpenAPI spec directly from threat-intel-beta.yaml — authentication, parameters and example payloads are preconfigured. Set the PSKey security value to your API key once and every request in the collection will use it.
Cursor iteration (JavaScript / Node)
Section titled “Cursor iteration (JavaScript / Node)”async function* allVulnerabilities(apiKey, platform = 'npm', perPage = 100) { const base = 'https://patchstack.com/database/api/beta/all'; let cursor = ''; // empty = bootstrap cursor mode
while (true) { const url = `${base}?platform=${platform}&per_page=${perPage}&cursor=${encodeURIComponent(cursor)}`; const res = await fetch(url, { headers: { PSKey: apiKey } }).then(r => r.json());
for (const vuln of res.vulnerabilities) { yield vuln; }
if (!res.cursor.has_more) return; cursor = res.cursor.next_cursor; }}
// usagefor await (const vuln of allVulnerabilities(process.env.PATCHSTACK_KEY)) { console.log(vuln.id, vuln.title);}Cursor iteration (PHP)
Section titled “Cursor iteration (PHP)”<?php
$apiKey = getenv('PATCHSTACK_KEY');$cursor = '';
do { $url = 'https://patchstack.com/database/api/beta/all' .'?platform=npm&per_page=100&cursor='.urlencode($cursor);
$ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['PSKey: '.$apiKey, 'Accept: application/json'], ]); $response = json_decode(curl_exec($ch), true); curl_close($ch);
foreach ($response['vulnerabilities'] as $vuln) { // handle $vuln }
$cursor = $response['cursor']['next_cursor'] ?? null;} while ($response['cursor']['has_more'] ?? false);Migration notes (v2 → beta)
Section titled “Migration notes (v2 → beta)”- Beta npm responses use nested objects (
product,cvss,cwe,capec,version_info) whereas the v2 shape is flat. Update parsers accordingly. ghsa_idwas renamed toghsaat the top level.direct_urlwas renamed tourl(the npm-flavoured shape exposes a single URL only).- The
descriptionfield was dropped for npm (the title already includes it). - The response body always contains a
vulnerabilitiesarray, plus eitherpagination(offset mode) orcursor(cursor mode).
More information
Section titled “More information”You can find more information about the Patchstack Threat Intelligence API on https://patchstack.com/for-hosts/. If you have integration questions, email dave.jong@patchstack.com.