A zero-dependency TypeScript client for the Snyk REST API (JSON:API).
- TypeScript-first — typed query parameters, resources, and JSON:API envelopes
- Snyk Open Source workflows — projects, issues, Package URL lookup, SBOM export, and Open Source settings
- Project lifecycle — get, update, and delete projects; delete targets
- Chainable resources —
snyk.org('id').issues({ effective_severity_level: ['critical'] }) - Dual package — ships CJS + ESM, works in Node.js and browsers
- Zero runtime dependencies — uses native
fetchandURLSearchParams - Auto-versioned — the
versionquery param is appended automatically to every request - Request events — hook into every HTTP request for logging and monitoring
- Semantic versioning — automated releases via Conventional Commits
npm install snyk-api-clientimport { SnykClient } from 'snyk-api-client';
const snyk = new SnykClient({ token: 'my-snyk-api-token' });
// List organizations
const { data: orgs } = await snyk.orgs();
console.log(orgs[0].attributes.name);
// Get a single org
const { data: org } = await snyk.org('org-id');
// List npm and Maven projects in an org
const { data: projects } = await snyk.org('org-id').projects({ types: ['npm', 'maven'] });
// List critical open issues
const { data: issues } = await snyk.org('org-id').issues({
effective_severity_level: ['critical'],
status: ['open'],
});
// Get package vulnerabilities by purl
const purl = 'pkg:npm/lodash@4.17.21';
const { data: pkgIssues } = await snyk.org('org-id').package(purl).issues();
// Export the latest project SBOM
const sbom = await snyk.org('org-id').project('project-id').sbom({
format: 'cyclonedx1.6+json',
});
// Get group orgs
const { data: groupOrgs } = await snyk.group('group-id').orgs();
// Get audit logs
const { data: logs } = await snyk.group('group-id').auditLogs({ events: ['org.user.add'] });The client uses the Snyk API token passed via the Authorization: token <api_token> header:
const snyk = new SnykClient({
token: 'my-snyk-api-token',
// Optional — defaults shown:
apiUrl: 'https://api.snyk.io',
apiPath: 'rest',
version: '2024-10-15',
});To generate a Snyk API token, go to Snyk → Account Settings → Auth Token.
The main client. All methods return Promises resolving to JSON:API envelopes.
// List all orgs (with optional filters)
await snyk.orgs({ slug: 'my-org', limit: 25 });
// Get a single org (await directly or call .get())
const { data: org } = await snyk.org('org-id');
const { data: org } = await snyk.org('org-id').get();// List projects in an org
await snyk.org('org-id').projects({ types: ['npm'], origins: ['github'] });
await snyk.org('org-id').projects({ target_id: ['target-id'] });
await snyk.org('org-id').projects({
business_criticality: ['high'],
lifecycle: ['production'],
});
// Get a single project
const { data: project } = await snyk.org('org-id').project('proj-id');
// Update mutable project attributes (the REST contract requires ownerId)
await snyk.org('org-id').project('proj-id').update({
attributes: { test_frequency: 'weekly', tags: [{ key: 'team', value: 'platform' }] },
ownerId: 'user-id', // use null for an unowned project
});
// Delete a project
await snyk.org('org-id').project('proj-id').delete();
// Export CycloneDX/SPDX JSON, or CycloneDX XML as a string
const sbom = await snyk.org('org-id').project('proj-id').sbom({
format: 'spdx2.3+json',
});// List issues in an org
await snyk.org('org-id').issues({
effective_severity_level: ['critical'],
status: ['open'],
});
await snyk.org('org-id').issues({ 'scan_item.id': 'proj-id', ignored: false });
await snyk.org('org-id').issues({ updated_after: '2024-01-01T00:00:00.000Z' });
// Get one issue; the same methods are available at group level
await snyk.org('org-id').issue('issue-id', { include_code_flows: true });
await snyk.group('group-id').issues({ type: 'package_vulnerability' });// List targets in an org
await snyk.org('org-id').targets({ is_private: false, exclude_empty: true });
// Get a single target
const { data: target } = await snyk.org('org-id').target('target-id');
// Delete a target (Snyk also deletes its projects)
await snyk.org('org-id').deleteTarget('target-id');// List organization or group memberships
await snyk.org('org-id').memberships({ role_name: 'org.admin' });
await snyk.group('group-id').memberships({ role_name: 'group.admin' });// Get direct issues affecting a package. Raw and encoded PURLs are accepted.
const purl = 'pkg:npm/lodash@4.17.21';
await snyk.org('org-id').package(purl).issues({ offset: 0, limit: 100 });// Org-level audit logs
await snyk.org('org-id').auditLogs({ events: ['project.delete'] });
await snyk.org('org-id').auditLogs({ from: '2024-01-01', to: '2024-12-31' });
// Group-level audit logs
await snyk.group('group-id').auditLogs({ user_id: 'user-id' });// List all groups
await snyk.groups({ limit: 10 });
// Get a single group (await directly or call .get())
const { data: group } = await snyk.group('group-id');
// List orgs within a group
await snyk.group('group-id').orgs({ slug: 'my-org' });
// Read organization-level Snyk Open Source settings
await snyk.org('org-id').openSourceSettings();Most JSON:API list endpoints use cursor-based pagination through links. Package issue lookup uses offset; audit logs use cursor and size.
let cursor: string | undefined;
const allProjects = [];
do {
const response = await snyk.org('org-id').projects({
limit: 100,
...(cursor ? { starting_after: cursor } : {}),
});
allProjects.push(...response.data);
// Extract cursor from next link (e.g. "?starting_after=xyz&...")
const nextLink = response.links?.next;
const nextUrl = typeof nextLink === 'string' ? nextLink : nextLink?.href;
const match = nextUrl?.match(/starting_after=([^&]+)/);
cursor = match?.[1];
} while (cursor);Subscribe to every HTTP request for logging, metrics, or debugging:
snyk.on('request', (event) => {
console.log(`[${event.method}] ${event.url} — ${event.durationMs}ms (${event.statusCode})`);
if (event.error) {
console.error('Request failed:', event.error.message);
}
});Event payload:
| Field | Type | Description |
|---|---|---|
url |
string |
Full URL requested |
method |
'GET' | 'POST' | 'PATCH' | 'DELETE' |
HTTP method |
startedAt |
Date |
Request start timestamp |
finishedAt |
Date |
Request end timestamp |
durationMs |
number |
Duration in milliseconds |
statusCode |
number? |
HTTP status code |
error |
Error? |
Error object if the request failed |
import { SnykApiError } from 'snyk-api-client';
try {
await snyk.org('nonexistent-id');
} catch (err) {
if (err instanceof SnykApiError) {
console.log(err.status); // 404
console.log(err.statusText); // 'Not Found'
console.log(err.message); // 'Snyk API error: 404 Not Found'
console.log(err.body); // parsed JSON:API error body, when available
}
}All domain types are exported:
import type {
// Client
SnykClientOptions,
RequestEvent,
// Envelopes
SnykResponse,
SnykCollectionResponse,
SnykLinks,
SnykPaginationParams,
// Organizations
SnykOrg,
SnykOrgAttributes,
SnykOrgsParams,
// Groups
SnykGroup,
SnykGroupsParams,
// Projects
SnykProject,
SnykProjectAttributes,
SnykProjectsParams,
SnykProjectStatus,
SnykProjectBusinessCriticality,
SnykProjectLifecycle,
SnykProjectEnvironment,
// Issues
SnykIssue,
SnykIssueAttributes,
SnykIssuesParams,
SnykIssueSeverity,
SnykIssueStatus,
// Targets
SnykTarget,
SnykTargetsParams,
// Memberships
SnykOrgMembership,
SnykGroupMembership,
SnykMembershipsParams,
// Packages
SnykPackage,
SnykPackageIssuesParams,
// Open Source / SBOM
SnykOpenSourceSettings,
SnykSbomParams,
SnykSbomDocument,
// Audit Logs
SnykAuditLog,
SnykAuditLogsParams,
} from 'snyk-api-client';See CONTRIBUTING.md for development guidelines.