Skip to content

API Reference

Sovereign GRC exposes a REST API at /api/v1/. As of v2.0.4 the backend ships 379 routes across 7 compliance frameworks, risk, vendor, incident, BCM, evidence, reports, and admin surfaces — far more than can be kept in sync by hand in a Markdown file.

Canonical API reference = your running backend

The authoritative, always-current reference is the OpenAPI spec generated by FastAPI itself, served from your own deployment:

Location What it is
/api/v1/openapi.json Machine-readable OpenAPI 3.1 schema
/api/v1/docs Interactive Swagger UI
/api/v1/redoc ReDoc-rendered reference

In development, these are exposed at http://localhost:8000/api/v1/docs. In production behind Cloudflare Access, they live at https://<your-domain>/api/v1/docs.

The sections below are a hand-curated tour of the most common surfaces for developers getting started. They are not exhaustive and they lag the backend — always cross-check against /openapi.json before coding.

Authentication

All API requests must include either:

  • a valid Cloudflare Access JWT in the CF_Authorization cookie or Cf-Access-Jwt-Assertion header (Cloudflare-mode deployments), or
  • a local JWT in the Authorization: Bearer <token> header (local-mode deployments — obtained via POST /api/v1/auth/login), or
  • an API key in the Authorization: Bearer sk-<key> header for machine-to-machine callers.

Base URL

https://your-domain.com/api/v1

Common Response Codes

Code Description
200 Success
201 Created
400 Bad Request — Invalid input
401 Unauthorized — Missing/invalid token
403 Forbidden — Insufficient permissions (or license required)
404 Not Found
422 Validation Error
500 Internal Server Error
503 Service Unavailable — e.g. evidence storage not configured

Frameworks

List Frameworks

GET /frameworks

Response:

{
  "items": [
    {
      "id": "uuid",
      "name": "SOC 2 Type II",
      "version": "2017",
      "description": "Trust Services Criteria",
      "control_count": 61
    }
  ]
}

Get Framework

GET /frameworks/{framework_id}

List Framework Controls

GET /frameworks/{framework_id}/controls

Organizations

List Organizations

GET /orgs

Create Organization

POST /orgs
Content-Type: application/json

{
  "name": "Acme Corp",
  "domain": "acme.com"
}

Get Organization

GET /orgs/{org_id}

Update Organization

PATCH /orgs/{org_id}
Content-Type: application/json

{
  "name": "Acme Corporation"
}

Delete Organization

DELETE /orgs/{org_id}

Users

Get Current User

GET /users/me

List Organization Users

GET /orgs/{org_id}/users

Create User

POST /orgs/{org_id}/users
Content-Type: application/json

{
  "email": "user@example.com",
  "name": "John Doe",
  "role": "analyst"
}

Roles: admin, auditor, analyst, viewer

Get User

GET /orgs/{org_id}/users/{user_id}

Update User

PATCH /orgs/{org_id}/users/{user_id}
Content-Type: application/json

{
  "role": "auditor"
}

Delete User

DELETE /orgs/{org_id}/users/{user_id}

Deactivate / Invite

POST /orgs/{org_id}/users/invite
POST /orgs/{org_id}/users/{user_id}/deactivate

Assessments

List Assessments

GET /orgs/{org_id}/assessments

Query Parameters: - framework_id - Filter by framework - status - Filter by status (pending, in_progress, completed, failed)

Create Assessment

POST /orgs/{org_id}/assessments
Content-Type: application/json

{
  "framework_id": "uuid",
  "name": "Q1 2026 SOC 2 Assessment",
  "scope": "Production environment"
}

Get Assessment

GET /orgs/{org_id}/assessments/{assessment_id}

Delete Assessment

DELETE /orgs/{org_id}/assessments/{assessment_id}

Execute Assessment

Start AI-powered assessment execution.

POST /orgs/{org_id}/assessments/{assessment_id}/execute

Resume Assessment

Resume a paused assessment.

POST /orgs/{org_id}/assessments/{assessment_id}/resume

Cancel Assessment

POST /orgs/{org_id}/assessments/{assessment_id}/cancel

Get Assessment Status

GET /orgs/{org_id}/assessments/{assessment_id}/status

Response:

{
  "status": "in_progress",
  "progress": 45,
  "controls_evaluated": 29,
  "controls_total": 64,
  "current_control": "CC6.1"
}


Findings

List Findings

GET /orgs/{org_id}/findings

Query Parameters: - assessment_id - Filter by assessment - status - Filter by status (pass, fail, partial, not_applicable) - severity - Filter by severity (critical, high, medium, low, info)

Get Finding

GET /orgs/{org_id}/findings/{finding_id}

Update Finding

PATCH /orgs/{org_id}/findings/{finding_id}
Content-Type: application/json

{
  "status": "pass",
  "remediation_notes": "Implemented MFA for all users"
}

Risk Management

The risk surface was restructured in v2.0 into four sibling namespaces under /orgs/{org_id}/risks/:

Namespace Purpose
/risks/register Risk-register entries (inherent + residual scoring)
/risks/kris Key Risk Indicators (metrics + thresholds)
/risks/fair FAIR quantitative analyses
/risks/scenarios Scenario-based risk models
/risks/heatmap Aggregated heatmap data for the UI
/risks/dashboard Summary metrics for the Risk dashboard

List / Create Risk Register Entries

GET  /orgs/{org_id}/risks/register
POST /orgs/{org_id}/risks/register

POST body:

{
  "title": "Third-party data breach",
  "description": "Risk of vendor experiencing data breach affecting our data",
  "category": "third_party",
  "likelihood": 3,
  "impact": 4,
  "owner_id": "uuid",
  "treatment": "mitigate"
}

Likelihood/Impact Scale: 1–5 (1 = Very Low, 5 = Very High) Categories: operational, financial, compliance, strategic, third_party, cyber, reputational Treatment: accept, mitigate, transfer, avoid

Get / Update / Delete Risk Register Entry

GET    /orgs/{org_id}/risks/register/{entry_id}
PATCH  /orgs/{org_id}/risks/register/{entry_id}
DELETE /orgs/{org_id}/risks/register/{entry_id}

Get Risk Heatmap

GET /orgs/{org_id}/risks/heatmap

Response:

{
  "inherent": [
    {"likelihood": 3, "impact": 4, "count": 5},
    {"likelihood": 2, "impact": 3, "count": 8}
  ],
  "residual": [
    {"likelihood": 2, "impact": 3, "count": 7},
    {"likelihood": 1, "impact": 2, "count": 6}
  ]
}

Key Risk Indicators (KRIs)

GET    /orgs/{org_id}/risks/kris
POST   /orgs/{org_id}/risks/kris
GET    /orgs/{org_id}/risks/kris/{kri_id}
PATCH  /orgs/{org_id}/risks/kris/{kri_id}
DELETE /orgs/{org_id}/risks/kris/{kri_id}
Content-Type: application/json

{
  "value": 245
}

Vendors

List Vendors

GET /orgs/{org_id}/vendors

Query Parameters: - status - Filter by status (active, inactive, pending, offboarded) - risk_tier - Filter by risk tier (critical, high, medium, low)

Create Vendor

POST /orgs/{org_id}/vendors
Content-Type: application/json

{
  "name": "Cloud Provider Inc",
  "category": "infrastructure",
  "risk_tier": "critical",
  "contact_email": "security@cloudprovider.com",
  "a2a_endpoint": "https://api.cloudprovider.com/.well-known/sovereign-a2a"
}

Get Vendor

GET /orgs/{org_id}/vendors/{vendor_id}

Update / Delete Vendor

PATCH  /orgs/{org_id}/vendors/{vendor_id}
DELETE /orgs/{org_id}/vendors/{vendor_id}
Content-Type: application/json

{
  "status": "active",
  "risk_rating": 85
}

See also: /orgs/{org_id}/vendors/assessments, /vendors/contracts, /vendors/stats.

A2A (Agent-to-Agent) Attestation

A2A is an MCP-over-HTTP protocol, not a bespoke REST endpoint. Instead of POST /vendors/{id}/attestation, an attestation is requested by speaking MCP to the vendor's A2A server (and to ours — we expose one too):

POST /api/v1/a2a/mcp
Content-Type: application/json

The client envelope follows the MCP 1.0 spec; the tools/call method invokes request_attestation with a frameworks argument:

{
  "method": "tools/call",
  "params": {
    "name": "request_attestation",
    "arguments": {
      "frameworks": ["SOC2_TYPE2", "ISO27001"],
      "requested_evidence": ["audit_report", "certificate", "controls_mapping"]
    }
  }
}

Health + metrics:

GET /api/v1/a2a/health
GET /api/v1/a2a/metrics

See the A2A CLI for a concrete client: python -m src.backend.a2a.cli attest ….


Incidents

List Incidents

GET /orgs/{org_id}/incidents

Query Parameters: - status - Filter by status (open, investigating, contained, resolved, closed) - severity - Filter by severity (critical, high, medium, low, info) - phase - Filter by NIST phase (detection, analysis, containment, eradication, recovery, post_incident)

Create Incident

POST /orgs/{org_id}/incidents
Content-Type: application/json

{
  "title": "Suspicious Login Activity",
  "description": "Multiple failed login attempts from unusual IP range",
  "category": "unauthorized_access",
  "severity": "high",
  "affected_systems": ["auth-server-01", "vpn-gateway"],
  "source": "siem_alert"
}

Categories: malicious_code, unauthorized_access, data_breach, denial_of_service, phishing, insider_threat, physical, other

Severity: critical, high, medium, low, informational

Get Incident

GET /orgs/{org_id}/incidents/{incident_id}

Response includes: - Incident details - Current phase - SLA status - Assigned tasks - Response timeline

Update Incident

PATCH /orgs/{org_id}/incidents/{incident_id}
Content-Type: application/json

{
  "severity": "critical",
  "commander_id": "uuid",
  "affected_records": 5000
}

Transition Incident Phase

Phase transitions are made with a standard PATCH on the incident:

PATCH /orgs/{org_id}/incidents/{incident_id}
Content-Type: application/json

{
  "phase": "containment",
  "notes": "Initial analysis complete, moving to containment"
}

Valid phases follow NIST 800-61: detection, analysis, containment, eradication, recovery, post_incident.

Get / Append Incident Timeline

GET  /orgs/{org_id}/incidents/{incident_id}/timeline
POST /orgs/{org_id}/incidents/{incident_id}/timeline

Response:

{
  "items": [
    {
      "timestamp": "2026-01-27T10:05:00Z",
      "event_type": "phase_transition",
      "description": "Phase changed from detection to analysis",
      "actor": "John Doe"
    }
  ]
}

Incident Tasks, Evidence, Metrics

GET,POST           /orgs/{org_id}/incidents/{incident_id}/tasks
PATCH,DELETE       /orgs/{org_id}/incidents/{incident_id}/tasks/{task_id}
POST               /orgs/{org_id}/incidents/{incident_id}/evidence/collect
GET                /orgs/{org_id}/incidents/{incident_id}/evidence/export
GET                /orgs/{org_id}/incidents/{incident_id}/metrics

Playbook execution has moved into the OPA policy surface; call POST /api/v1/opa/decisions with the incident context to run a ransomware / phishing / DoS playbook. See the Swagger UI for the full request envelope.


Business Continuity Management

List Business Processes

GET /orgs/{org_id}/bcm/processes

Create Business Process

POST /orgs/{org_id}/bcm/processes
Content-Type: application/json

{
  "name": "Order Fulfillment",
  "description": "End-to-end order processing and delivery",
  "criticality": "business_critical",
  "rto_hours": 4,
  "rpo_hours": 1,
  "mtd_hours": 24,
  "owner_id": "uuid"
}

Criticality: mission_critical, business_critical, business_operational, administrative

List / Create Dependencies

GET    /orgs/{org_id}/bcm/dependencies
POST   /orgs/{org_id}/bcm/dependencies
PATCH  /orgs/{org_id}/bcm/dependencies/{dependency_id}
DELETE /orgs/{org_id}/bcm/dependencies/{dependency_id}

Dependency Graph

Returns the full node/edge graph for the Bow-Tie / BCM visualization.

GET /orgs/{org_id}/bcm/dependency-graph

Response:

{
  "nodes": [
    {"id": "process-1", "type": "process", "name": "Order Fulfillment"},
    {"id": "asset-1", "type": "asset", "name": "PostgreSQL Primary"}
  ],
  "edges": [
    {"source": "process-1", "target": "asset-1", "dependency_type": "requires"}
  ]
}

Process → DR Plan Generation

Generates a tiered disaster-recovery plan (RTO/RPO-sequenced) for a single business process by walking its dependency graph.

POST /orgs/{org_id}/bcm/processes/{process_id}/generate-dr-plan

Response:

{
  "tiers": [
    {"tier": 1, "rto_hours": 1, "items": [{"type": "asset", "name": "Core Database"}]},
    {"tier": 2, "rto_hours": 4, "items": [{"type": "process", "name": "Order Fulfillment"}]}
  ]
}

Recovery Plans

GET,POST          /orgs/{org_id}/bcm/recovery-plans
GET,PATCH,DELETE  /orgs/{org_id}/bcm/recovery-plans/{plan_id}

Climate-Risk Analysis

POST /orgs/{org_id}/bcm/climate-risk

Analyzes the dependency graph for physical / regional / climate concentration risk. Returns single-points-of-failure and concentration warnings inline — the previous GET /bcm/spof endpoint has been folded into this response.


Evidence

List Evidence

GET /orgs/{org_id}/evidence

Query Parameters: - finding_id - Filter by finding - assessment_id - Filter by assessment

Get Upload URL

Get a pre-signed URL to upload evidence to R2.

POST /orgs/{org_id}/evidence/upload-url
Content-Type: application/json

{
  "filename": "soc2-report-2026.pdf",
  "content_type": "application/pdf",
  "finding_id": "uuid"
}

Response:

{
  "upload_url": "https://...",
  "evidence_id": "uuid",
  "expires_at": "2026-01-27T11:00:00Z"
}

Get Download URL

GET /orgs/{org_id}/evidence/download-url?key=<object_key>

Takes the evidence object key as a query parameter and returns a short-lived presigned URL. Requires the evidence store (Cloudflare R2) to be configured — otherwise returns 503 storage unavailable.

Integrity + Metadata

GET  /orgs/{org_id}/evidence/metadata?key=<object_key>
POST /orgs/{org_id}/evidence/verify

Bulk Import

POST /orgs/{org_id}/evidence-import/csv
POST /orgs/{org_id}/evidence-import/json

Reports

List / Create Reports

GET  /orgs/{org_id}/reports
POST /orgs/{org_id}/reports
Content-Type: application/json

{
  "type": "compliance_summary",
  "assessment_id": "uuid",
  "format": "pdf"
}

Report Types: compliance_summary, gap_analysis, risk_register, incident_summary, bcm_impact_analysis

Formats: pdf, xlsx, json, html

Preview, Get Detail, Download

GET /orgs/{org_id}/reports/preview
GET /orgs/{org_id}/reports/{report_id}
GET /orgs/{org_id}/reports/{report_id}/download

Health & Status

Health Check

GET /health

Response:

{
  "status": "healthy",
  "version": "1.0.0",
  "services": {
    "database": "healthy",
    "redis": "healthy",
    "opa": "healthy",
    "steampipe": "healthy"
  }
}


Error Responses

All errors follow this format:

{
  "detail": "Error message describing what went wrong",
  "code": "ERROR_CODE",
  "field": "field_name"  // Optional, for validation errors
}

Common Error Codes

Code Description
UNAUTHORIZED Missing or invalid authentication
FORBIDDEN User lacks required permission
NOT_FOUND Resource does not exist
VALIDATION_ERROR Input validation failed
CONFLICT Resource already exists
RATE_LIMITED Too many requests

Rate Limits

Endpoint Limit
Default 100 requests/minute
Assessment execution 5 concurrent
Report generation 10/hour
Evidence upload 50/hour

Rate limit headers are included in all responses: - X-RateLimit-Limit - X-RateLimit-Remaining - X-RateLimit-Reset


OpenAPI Specification

The full OpenAPI 3.0 specification is available at:

GET /api/v1/openapi.json

Interactive API documentation (Swagger UI):

GET /api/v1/docs