PACCI CVMS

PACCI CVMS API Documentation

Last updated

Quick start

Fetch organization-scoped security aggregation in one call. This is the fastest path from an authenticated client to dashboard-ready totals.

typescript
const base = process.env.NEXT_PUBLIC_APP_URL ?? "https://api.pacci-cvms.com";

await fetch(`${base}/api/manage-assets`, {
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
    "x-customer-id": "<customer_id>",
  },
});
  • Requires an authenticated session (NextAuth cookies are sent when credentials: "include" is set).
  • Requires x-customer-id (or x-pacci-customer-id) on every request: the handler returns 400 if it is missing. Use your organization id for customer portal users; for MSP staff, use the active organization id (same value the UI stores in the customer cookie).

Overview

PACCI CVMS exposes HTTP APIs under the Next.js App Router. For **organization-wide rollups** (deduplicated union of visible unified asset groups), use **GET /api/manage-assets** with an authenticated session and **x-customer-id**. The in-app Security Overview uses **GET /api/dashboard/overview** plus companion routes **GET /api/dashboard/overview/sonar** and **GET /api/dashboard/overview/sla** (session org scope only; no customer header). Per-group breakdowns use **GET /api/security-overview**.

Base URL (production)

https://api.pacci-cvms.com

In local development, use your app origin (e.g. http://localhost:3000) with the same path prefixes.

Authentication

APIs rely on NextAuth session cookies for browser and same-origin clients. Include credentials on every request so the session is sent.

For programmatic access from tools such as Postman, use either a valid session cookie from an authenticated browser session or a Bearer token where your deployment supports it (e.g. JWT from your IdP), consistent with your PACCI auth configuration.

javascript
fetch(url, {
  credentials: "include",
});

Headers & org scope

Most JSON APIs expect Content-Type on writes. How the active organization is chosen depends on the route.

  • Content-Type: application/json for JSON request bodies (POST/PUT).
  • Always required for manage-assets: x-customer-id or x-pacci-customer-id must be the target organization id. The handler returns 400 if the header is missing. Customer portal users must use their own org id (403 otherwise).
  • Optional for security-overview: the same headers override org when present. If omitted, the server uses the organization already resolved on the session (e.g. customer portal users, or MSP after selecting a customer in the UI). If no organization id can be resolved, you get 400 with a "missing organization scope" style message.
  • Dashboard overview family: GET /api/dashboard/overview, GET /api/dashboard/overview/sonar, and GET /api/dashboard/overview/sla do not read x-customer-id; they use getCustomerContext only (MSP must have an active customer selected in-session).

Primary endpoint

Manage Assets (primary endpoint)

This is the primary endpoint powering all security dashboards, executive summaries, and reporting across PACCI CVMS. It returns unified Application Code Security and Offensive Security aggregates for the active customer context.

Endpoint

GET https://api.pacci-cvms.com/api/manage-assets

Application Code Security

Includes contributions from:

  • SonarQube / SonarCloud (SAST)
  • Snyk (SCA)
  • Checkmarx (SAST, SCA, and related AppSec categories)

Offensive Security

Includes:

  • DAST scan results (e.g. Checkmarx DAST)
  • Manual VAPT / vault-synced findings

Response (authoritative)

Field names use camelCase. Severity blocks roll up open issues in the **union** of all visible unified asset groups (AppSec vs OffSec classification). Checkmarx AppSec counts prefer **live CxOne scan-summary** totals when the integration is configured; they fall back to synced DB findings if live data is unavailable. offensiveFindings lists open offensive items (Secure Vault synced rows and Checkmarx DAST); source is secure_vault or DAST. category is Offensive Security for both.

json
{
  "applicationCodeSecurity": {
    "total": 1234,
    "critical": 45,
    "high": 210,
    "medium": 700,
    "low": 279
  },
  "offensiveSecurity": {
    "total": 320,
    "critical": 12,
    "high": 80,
    "medium": 150,
    "low": 78
  },
  "offensiveFindings": [
    {
      "id": "sv-example-id",
      "title": "Example finding",
      "severity": "High",
      "description": null,
      "source": "secure_vault",
      "category": "Offensive Security",
      "createdAt": "2026-01-15T12:00:00.000Z",
      "cweMappings": null,
      "targetUrl": null,
      "riskImpact": null,
      "recommendation": null,
      "folderId": "folder-uuid",
      "folderPath": "/Reports",
      "sourceFileName": null,
      "syncedAt": "2026-01-15T12:00:00.000Z",
      "checkmarxProjectId": null,
      "checkmarxProjectName": null
    }
  ]
}

Behavior

  • Required header: x-customer-id or x-pacci-customer-id must match an active customer id. Customer portal users may only use their own organization id (403 otherwise).
  • Aggregates Sonar/Snyk/Checkmarx AppSec and offensive sources (vault + DAST) within visible unified groups for that organization.
  • Requires an org-scoped role with read access (same family as other org security APIs).
  • After **Sonar** or **Checkmarx** catalog sync, projects removed in the upstream tool are pruned in PACCI (including sonar_project / checkmarx_appsec group members where applicable), so manage-assets totals stay aligned without manual cleanup.

Example request

bash
curl -X GET https://api.pacci-cvms.com/api/manage-assets \
  -H "Content-Type: application/json" \
  -b "next-auth.session-token=..." \
  -H "x-customer-id: <customer_id>"

Related: per-group overview

GET https://api.pacci-cvms.com/api/security-overview

  • Returns per unified asset group application vs offensive severity totals (same live Checkmarx / DAST / Sonar pipeline as manage-assets, but **one row per group** — summing groups can double-count if the same asset appears in multiple groups).
  • x-customer-id is optional; if omitted, org scope comes from the session. If neither resolves to an organization id, the response is 400.
  • For deduplicated org-wide rollups and the offensive findings list, use GET /api/manage-assets (requires x-customer-id, includes offensiveFindings).

Core routes reference

Read-heavy endpoints most integrations and internal tools call. All require an authenticated session unless noted.

GET /api/manage-assets

Org-wide AppSec + OffSec severity blocks and offensiveFindings. Requires x-customer-id (or x-pacci-customer-id) + credentials: "include".

GET /api/security-overview

JSON groups[] with per-group totals and last_updated. Optional customer header; needs resolvable org scope (session or header).

GET /api/dashboard/overview

Core payload for the in-app Security Overview: KPI-style counters, donuts (provider + severity slices for charts), severity totals (criticalSeverity lowSeverity), and topAssets. Uses session org scope only — no x-customer-id. SLA breach counts are not included here; load GET /api/dashboard/overview/sla separately.

When mergeSonar is true (full-customer scope), SonarCloud open totals and topAssets are provisional until the client merges GET /api/dashboard/overview/sonar. Group-scoped dashboards omit Sonar merge and compute topAssets from the overview response alone.

json
{
  "scopedToAssetGroups": false,
  "assetGroups": 3,
  "totalLinkedAssets": 42,
  "vulnerabilitiesOpen": 120,
  "vulnerabilitiesTotal": 400,
  "remediated": 280,
  "criticalSeverity": 5,
  "highSeverity": 20,
  "mediumSeverity": 45,
  "lowSeverity": 50,
  "lastUpdated": "2026-05-12T12:00:00.000Z",
  "mergeSonar": true,
  "donuts": {
    "providerMode": "full",
    "provider": [
      { "key": "vault", "name": "Secure Vault", "value": 12, "fill": "#0891b2" },
      { "key": "snyk", "name": "Snyk", "value": 40, "fill": "#db2777" }
    ],
    "severity": [
      { "key": "critical", "name": "Critical", "value": 5, "fill": "#dc2626" },
      { "key": "high", "name": "High", "value": 20, "fill": "#ea580c" }
    ]
  },
  "topAssets": []
}

GET /api/dashboard/overview/sonar

SonarCloud rollups (sonarOpen, per-project counts, etc.) plus merged topAssets for full-customer scope. Same auth and org rules as GET /api/dashboard/overview. Typically called right after the overview when mergeSonar is true.

GET /api/dashboard/overview/sla

Returns { "breaches": <number> } — count of open vulnerabilities past SLA in the same merged scope as the Vulnerabilities tab. Same session-only org resolution as the other dashboard routes.

GET /api/application-code-security/summary

Lightweight ACS landing totals (Snyk, Checkmarx, SonarCloud open severities). Cached; optional query ?forceRefresh=true. Session org scope (customerIdOr400).

GET /api/asset-groups

Unified groups (MSP-wide + org-owned) visible to the current user. No customer header; org comes from the session. Use PUT /api/asset-groups with replaceMode to mutate (role-gated).

Asset groups

Unified groups link Secure Vault folders, application code security assets (Sonar, Snyk, Checkmarx AppSec), and Checkmarx DAST environments.

GET /api/asset-groups — Returns groups visible in the current context:

  • MSP-wide groups: customerId = null
  • Org-owned groups: customerId set to the organization id

PUT /api/asset-groups — Replaces or updates groups according to replaceMode (all, vault_folders, dast_environments).

For customer_admin, only org-owned rows are modified; MSP-wide groups in the list are read-only in Manage Assets and are not recreated as org-owned (avoids duplicate groups).

Customers

Customer records and nested user management for MSP context switching and org initialization.

  • GET /api/customers — List customers (MSP)
  • POST /api/customers — Create customer (role-gated)
  • Related: GET/PATCH /api/customers/[customerId], /api/customers/[customerId]/users

Secure Vault

Secure Vault stores PDF reports and synced findings. File payloads are written to disk on the application host.

Production deployments should set SECURE_VAULT_UPLOAD_DIR to a persistent, writable directory. Serverless filesystems (e.g. default Vercel) are not suitable for durable binary storage unless you use external object storage.

  • Vault-oriented reads/writes are exposed under routes such as GET /api/folders, GET /api/secure-vault/findings, and PDF upload via POST /api/folders/files (multipart). Conceptually, GET /api/secure-vault and POST /api/secure-vault/upload map to this surface in product documentation.

Integrations & sync

Validate credentials, then trigger catalog sync so PACCI matches SonarCloud, Snyk, and Checkmarx One. Sync routes require an admin role and an active organization on the session (same rules as Setup).

Validation (pre-flight)

  • POST /api/integrations/sonarqube/validate — SonarQube / SonarCloud connectivity and token checks
  • POST /api/integrations/snyk/validate — Snyk API configuration
  • POST /api/integrations/checkmarx/validate — Checkmarx One realm and client credentials

Product docs may abbreviate Sonar as /integrations/son/validate; the deployed route is sonarqube.

Catalog sync (writes PACCI DB)

  • POST /api/integrations/sonarqube/sync — Pull Sonar projects and issues for the active session organization. After a successful run, Sonar projects that no longer exist upstream are pruned in PACCI (synced Project rows, findings, and sonar_project asset-group members).
  • POST /api/integrations/snyk/sync — Refresh Snyk projects and org-level summaries for the active organization.
  • POST /api/integrations/checkmarx/sync — Sync Checkmarx One catalog and findings. AppSec code projects no longer assigned in Cx are pruned (including checkmarx_appsec group members for those PACCI project ids).

MSP users must select a customer before calling sync (session customerId); otherwise the API returns 400 with a "no active organization" message.

Architecture notes

PACCI uses a hybrid multi-tenant model for asset groups, integrations, and scoped APIs.

MSP-wide data

  • customerId = null
  • Shared across organizations (e.g. template unified groups, filtered by what each org can see)

Customer-owned data

  • customerId = <org_id>
  • Scopes folders, projects, org-owned asset groups, and customer-scoped API results

Rules

  • Customer admins can view shared plus owned data where the product allows
  • Customer admins can modify only owned data (not MSP-wide templates via full replace in Manage Assets)
  • MSP admins retain global management capabilities

Common mistakes

Frequent integration issues and how to avoid them.

  • Missing credentials: "include"Browser requests omit the session cookie → 401 Unauthorized.
  • Missing x-customer-id / x-pacci-customer-idOn GET /api/manage-assets you get 400 Missing x-customer-id header. On other org routes, MSP flows may resolve the wrong scope → empty or incorrect data.
  • Modifying MSP-wide asset groups as customer_admin — Full replace and some writes are forbidden or no-op for shared rows; use org-owned groups or ask an MSP admin.
  • Stale local builds — After backend or route changes, rebuild .next (e.g. next build / dev restart) so App Router handlers and middleware match the server you are testing.

Error handling

Errors use JSON bodies with an error string; some responses include a details field for debugging.

json
{
  "error": "Unauthorized"
}
  • 401 — Missing or invalid session
  • 403 — Authenticated but not allowed for this resource
  • 400 — Malformed body or parameters

Examples

Minimal patterns for browser and cURL clients.

fetch — security aggregation

javascript
await fetch("https://api.pacci-cvms.com/api/manage-assets", {
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
    "x-customer-id": "<customer_id>",
  },
});

fetch — asset groups

javascript
await fetch("/api/asset-groups", {
  credentials: "include",
});

cURL — manage assets

bash
curl -X GET https://api.pacci-cvms.com/api/manage-assets \
  -H "Content-Type: application/json" \
  -H "x-customer-id: <customer_id>"