REST API

The API is served by crypto-discovery-api (default :8080) and versioned under /api/v1. Responses are JSON.

Authentication

Three access levels, enforced by middleware:

  • PublicGET /healthz and the sign-in / initial-setup routes.
  • User session (cookie) — every read, CBOM, compliance, knowledge, settings, node, GitHub, and issue endpoint. You sign in through the dashboard and the browser carries the session cookie; a missing or invalid session returns 401.
  • Node credential — scan ingest and node-discovery endpoints. Send the node-issued credential as X-API-Key: <credential> (an Authorization: Bearer <credential> header is also accepted). An invalid credential returns 401.

Errors

Errors are returned as JSON:

{ "error": "message describing what went wrong" }
StatusMeaning
400Invalid request.
401Missing or invalid authentication.
403Authenticated but not permitted.
409Conflict with current state.
429Per-IP rate limit exceeded.
500Server error.
503Service unavailable (e.g. the database is unreachable).

The per-IP rate limit is configurable with --rate-limit-requests and --rate-limit-window (see Configuration).

Health

curl -s http://localhost:8080/healthz
# {"status":"ok"}  (200, or 503 if the database ping fails)

Ingest a scan (node credential)

curl -s -X POST http://localhost:8080/api/v1/scans \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: ndc_example_node_credential' \
  --data-binary @out/inventory.json

The body is the normalized inventory the scanner writes with --json (see Schemas). A successful upload returns 202 Accepted.

Read endpoints (session)

Method and pathReturns
GET /api/v1/orgs/{org}/summaryOrganization posture summary.
GET /api/v1/orgs/{org}/reposRepositories in an organization.
GET /api/v1/orgs/{org}/top-risksTop risks across an organization.
GET /api/v1/orgs/{org}/assetsCryptographic asset inventory.
GET /api/v1/repos/{repoID}/latest-scanLatest scan for a repository.
GET /api/v1/repos/{repoID}/scansScan history for a repository.
GET /api/v1/repos/{repoID}/findingsFindings for a repository.
GET /api/v1/repos/{repoID}/contextRepository context.

Compliance and policy (session)

Method and pathReturns
GET /api/v1/orgs/{org}/compliance/reportCompliance report across active frameworks.
GET /api/v1/orgs/{org}/compliance/pqcPost-quantum readiness.
GET /api/v1/orgs/{org}/policy/frameworksAvailable policy frameworks.

CBOM export (session)

Method and pathReturns
GET /api/v1/orgs/{org}/cbomProduct CBOM read model.
GET /api/v1/orgs/{org}/cbom/standards/{standardID}Standards export (e.g. cyclonedx-1.7, cyclonedx-1.6).

See Export a CBOM for the export contents.

Audit (session)

Method and pathReturns
GET /api/v1/orgs/{org}/audit/snapshotsAudit snapshots.
GET /api/v1/orgs/{org}/audit/snapshots/{snapshotID}A single snapshot.
GET /api/v1/orgs/{org}/audit/snapshots/{snapshotID}/export.jsonSnapshot export.

Knowledge (session)

These power the dashboard, the assistant, and the MCP tools. Each returns summary, sources, and limitations alongside its payload (limit defaults to 50, clamps at 200):

  • POST /api/v1/orgs/{org}/knowledge/find-crypto-risks
  • POST /api/v1/orgs/{org}/knowledge/finding-context
  • POST /api/v1/orgs/{org}/knowledge/repo-posture
  • POST /api/v1/orgs/{org}/knowledge/migration-candidates
  • POST /api/v1/orgs/{org}/knowledge/developer-context

Schemas

Field names below are the JSON keys the API uses; values are illustrative. Fields marked optional are omitted when empty.

Scan inventory (ingest body)

The body of POST /api/v1/scans — normally the file the scanner wrote with --json:

{
  "scan_id": "01H...",
  "org_name": "acme",
  "repo_name": "payments-service",
  "scanned_path": "./payments-service",
  "generated_at": "2026-01-01T12:00:00Z",
  "tool_version": "0.1.0",
  "commit_sha": "a7c3f9...",
  "summary": {
    "files_scanned": 128,
    "total_findings": 17,
    "by_severity": { "critical": 2, "high": 5 },
    "by_category": { "weak-algorithm": 9 },
    "by_rule": { "crypto.weak.rsa-1024": 3 },
    "languages": ["go", "python"]
  },
  "modules": [
    { "module_id": "native/pqc-readiness", "kind": "native", "status": "ok", "findings": 4 }
  ],
  "findings": [ /* Finding objects, see below */ ]
}

org_name, commit_sha, and modules are optional.

Finding

Returned by GET /api/v1/repos/{repoID}/findings (an array) and embedded in the inventory:

{
  "id": "f_01H...",
  "category": "weak-algorithm",
  "rule_id": "crypto.weak.rsa-1024",
  "title": "RSA-1024 key",
  "severity": "critical",
  "confidence": "high",
  "file_path": "legacy/sign.py",
  "line": 91,
  "algorithm": "RSA-1024",
  "key_size_bits": 1024,
  "library": "crypto/rsa"
}

Optional fields include canonical_rule_id, source_rule_id, effective_confidence, language, symbol, api, hash, cipher_mode, randomness_source, material_reference_type, and custody_provider.

Organization summary

Returned by GET /api/v1/orgs/{org}/summary:

{
  "org_name": "acme",
  "repository_count": 12,
  "scan_count": 34,
  "total_findings": 489,
  "by_severity": { "critical": 7, "high": 22 },
  "top_rules": [ /* most frequent rules */ ]
}