Skip to main content
CMDashCybersecurity Maturity Dashboard
DocsDevelopers@cmdash/api-sdk — CMDash Public API client (v1 + v2)

@cmdash/api-sdk — CMDash Public API client (v1 + v2)

Official TypeScript client for the CMDash Public API — v1 under client.<namespace>, and v2 (current — #575) under client.v2.<namespace> (ROADMAP-V50 item 33). Zero dependencies — uses the global fetch every supported Node runtime (18+) ships, same choice packages/gate-cli already made.

Hand-written, not generated. No OpenAPI code-generator is a dependency anywhere in this monorepo, and none may be added — so this is a small, fully reviewed client for the documented surface instead of a generated one. test/method-coverage.test.ts is what keeps it honest: it statically parses every route out of the real public-*.controller.ts (v1) and v2/public-*.controller.ts (v2) files and fails CI if a route exists with no SDK method, or an SDK method exists for a route that's gone — for either version. See src/index.ts's header for the full reasoning.

For what "v1" commits to (and what forced v2), see docs/developers/public-api-versioning.md. For the live, always-current interactive docs, see /api/v1/reference / /api/v2/reference (ReDoc) on your CMDash instance.

Install

This package is not yet published to npm — there is no sdk-v* tag yet (see .github/workflows/publish-sdk.yml, which publishes only when one is cut), so npm i @cmdash/api-sdk does not resolve anything today.

Install from this repository (works today)

npm i github:bgovanlu/cmdash#path:packages/sdk-js does not work — npm's path: fragment only resolves a subdirectory for a git dependency that itself contains a package.json with no monorepo-relative build step, and this one needs tsc run first. Pack a real tarball instead (this repository is currently private, so cloning it requires repository access):

bash
git clone https://github.com/bgovanlu/cmdash.git
cd cmdash/packages/sdk-js
npm install
npm run build
npm pack                 # writes cmdash-api-sdk-<version>.tgz in this directory (the version in package.json)

# then, from the project that wants the SDK:
npm install /path/to/cmdash-api-sdk-<version>.tgz
<!-- when-published -->

When published

Once sdk-v* has a tag and .github/workflows/publish-sdk.yml has pushed it to npm:

bash
npm i @cmdash/api-sdk
<!-- /when-published -->

Get an API key

Settings → API Keys → Create API Key, with whichever permission scopes the calls you plan to make require (see docs/developers/public-api-reference.md for the scope each endpoint needs). Store it securely — never commit it.

Usage

typescript
import { CmdashClient } from '@cmdash/api-sdk';

const client = new CmdashClient({
  apiKey: process.env.CMDASH_API_KEY!,
  // baseUrl: 'https://app.cmdash.net/api', // default; override for on-prem
});

// The unprefixed namespace is API v2 — the current version.
const posture = await client.posture.getLatest();
console.log(posture?.score, posture?.grade);

const { risks, total } = await client.risks.list({ status: 'OPEN', limit: 20 });

const gate = await client.gate.evaluate();
if (!gate.pass) {
  console.error('Posture gate failed:', gate.failures.map((f) => f.reason));
  process.exitCode = 1;
}

// v2-only resources, same unprefixed namespace:
const { secret } = await client.webhooks.create({ url: 'https://example.com/hook', events: ['posture.changed'] });

// `client.v2.*` is the same object, spelled explicitly.
// `client.v1.*` is the deprecated version (Sunset: 24 Feb 2027).

Migrating to the v2 default

Before ROADMAP-V100 I4, client.<resource> was v1 and v2 lived at client.v2.<resource>. It is now the other way round: the unprefixed namespace is v2, and v1 moved — intact — to client.v1.<resource>.

  • Keep exactly the previous behaviour: client.risks → client.v1.risks. A find-and-replace; nothing else changes. The client prints one console.warn per instance the first time it issues a /v1/ request, naming the sunset date; pass { suppressDeprecationWarnings: true } once you have read it.

  • Move to v2 instead (recommended): leave your call sites alone. On the five resources that exist in both versions (posture, compliance, risks, integrations, gate) the request, the key scopes and the response shapes are identical, with exactly two exceptions — and TypeScript will point at both of them for you, because they are the only two places the return TYPE changed:

    callv1v2
    compliance.getFrameworkControls(unknownSlug)resolves { error: 'Framework not found' }, HTTP 200rejects CmdashApiError (404)
    integrations.getHealth(unknownId)resolves { error: 'Integration not found' }, HTTP 200rejects CmdashApiError (404)

    If your project still compiles after upgrading, there is no behavioural difference left to find. client.v2.* keeps working and is the same object as the unprefixed name, so existing v2 call sites need no edit.

// v2 (current — prefer this for new integrations, see #575): const v2posture = await client.v2.posture.getLatest(); const { secret } = await client.v2.webhooks.create({ url: 'https://example.com/hook', events: ['posture.changed'] });

// ROADMAP-V100 I13 — verify a brand-new endpoint before any real event reaches it. await client.v2.webhooks.test(webhookId);

code

### Verifying an inbound webhook's signature (ROADMAP-V100 I12)

`verifyWebhookSignature` is a standalone export — it runs entirely on the
RECEIVING end, over a delivery your server got, not over a call this client
makes — so it is not a method on `CmdashClient`:

```ts
import { verifyWebhookSignature } from '@cmdash/api-sdk';

// req.rawBody MUST be the raw bytes received, not a re-serialized JSON.parse.
const ok = verifyWebhookSignature(
  req.rawBody,
  process.env.CMDASH_WEBHOOK_SECRET!,
  req.headers['x-cmdash-signature'] as string,
);
if (!ok) return res.status(401).send('invalid signature');

Does the timing-safe compare and the replay-window check for you — do not hand-roll this. See docs/webhook-events.md for the full wire contract.

Every method throws CmdashApiError (a real HTTP error response — status code, error, message, requestId from the server's actual error envelope) or CmdashClientError (couldn't reach the server, or got back something that isn't the documented envelope shape) — never a silent undefined.

For CI pipelines specifically, prefer @cmdash/gate-cli (a purpose-built CLI/GitHub Action over POST /v2/gate/evaluate) unless you need the result inside a larger JS/TS program — client.gate.evaluate() here exists for that latter case.

Coverage of the v1 and v2 surfaces

Every endpoint in docs/developers/public-api-reference.md (generated, drift-checked — npm run docs:public-api:check) has a corresponding method here, in both client.v1.<namespace> (v1) and client.<namespace> / client.v2.<namespace> (v2 — the same object under two names), verified by test/method-coverage.test.ts. Two v1 endpoints resolve rather than reject on a not-found ID (compliance.getFrameworkControls, integrations.getHealth) — this mirrors real, current v1 server behavior (HTTP 200 with an { error } body) rather than papering over it; their v2 counterparts reject with a real CmdashApiError (404) instead. See docs/developers/public-api-versioning.md's "Error shapes" section. v2 also adds five resources with no v1 equivalent — client.webhooks, client.reports, client.auditLogs, client.collector and client.evidence.

This page is the product manual, published from the repository at packages/sdk-js/README.md. Customers read the same text inside CMDash under Help. Last updated October 9, 2026.

@cmdash/api-sdk — CMDash Public API client (v1 + v2) — CMDash Docs