Skip to content

NPM features (Beta)

The Beta surface extends the Threat Intelligence API ahead of GA. It runs at a separate base URL, ships its own OpenAPI spec, and is available to selected partners working directly with Patchstack. The shared endpoints (/latest, /product/{type}/{name}/{version}, /product/{type}/{name}/{version}/exists, /batch) behave the same as the stable API but accept extra parameters and return a nested response shape. This page documents only what’s new — for the full spec including npm-flavour examples, see the auto-generated reference. Contact us if you’d like access.

https://patchstack.com/database/api/beta/
AdditionWhere it applies
GET /allNew endpoint — cursor-paginated full listing of every advisory, scoped by ?platform=.
?platform=npmList endpoints (/all, /latest, /product/...). Default is wordpress; case-insensitive.
?cursor=/all and /latest — cursor pagination alongside the existing ?page=&per_page=.
?include=detailsList endpoints — adds an advisory_details markdown field to each item (npm).
Nested response shapeAll list endpoints — product, cvss, cwe, version_info objects in place of the v2 flat shape.

The full Beta schema (every endpoint, parameter, response example) lives in the auto-generated reference.

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 versioned URLs ship.

/all and /latest support two independent strategies. Use whichever fits your client:

  • Offset (?page=&per_page=) — returns a pagination block 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 advisories land while you’re paging.
  • Cursor (?cursor=) — returns a cursor block with next_cursor, has_more, per_page. Stable under concurrent inserts and faster at any depth. No total count (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.

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 }
}

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.

In addition to the stable error codes, Beta returns:

StatusMeaning
422 Unprocessable EntityInvalid parameter combination (e.g. cursor + page), invalid platform, or per_page > 500.
  • Beta npm responses use nested objects (product, cvss, cwe, capec, version_info) whereas the v2 shape is flat. Update parsers accordingly.
  • ghsa_id was renamed to ghsa at the top level.
  • direct_url was renamed to url (the npm-flavoured shape exposes a single URL only).
  • The description field was dropped for npm (the title already includes it).
  • The response body always contains a vulnerabilities array, plus either pagination (offset mode) or cursor (cursor mode).

Terminal window
# Latest 24h, npm
curl '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 text
curl 'https://patchstack.com/database/api/beta/product/npm/axios/0.21.4?include=details' \
-H 'PSKey: <your-api-key>'
# Boolean-only exists check
curl 'https://patchstack.com/database/api/beta/product/npm/axios/0.21.4/exists' \
-H 'PSKey: <your-api-key>'
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;
}
}
// usage
for await (const vuln of allVulnerabilities(process.env.PATCHSTACK_KEY)) {
console.log(vuln.id, vuln.title);
}
<?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);

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.